pymembar 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pymembar-0.1.2/LICENSE.txt +28 -0
- pymembar-0.1.2/MANIFEST.in +4 -0
- pymembar-0.1.2/PKG-INFO +139 -0
- pymembar-0.1.2/README.md +112 -0
- pymembar-0.1.2/include/membar.h +46 -0
- pymembar-0.1.2/membar/__init__.py +11 -0
- pymembar-0.1.2/membar/__init__.pyi +57 -0
- pymembar-0.1.2/membar/py.typed +0 -0
- pymembar-0.1.2/membarmodule.c +312 -0
- pymembar-0.1.2/pymembar.egg-info/PKG-INFO +139 -0
- pymembar-0.1.2/pymembar.egg-info/SOURCES.txt +17 -0
- pymembar-0.1.2/pymembar.egg-info/dependency_links.txt +1 -0
- pymembar-0.1.2/pymembar.egg-info/top_level.txt +1 -0
- pymembar-0.1.2/pyproject.toml +52 -0
- pymembar-0.1.2/setup.cfg +4 -0
- pymembar-0.1.2/setup.py +27 -0
- pymembar-0.1.2/src/membar.c +295 -0
- pymembar-0.1.2/tests/test_basic.py +68 -0
- pymembar-0.1.2/tests/test_logging.py +189 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, Fabian Krumm
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
pymembar-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pymembar
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Memory barrier utilities for Python - provides wmb, rmb, and fence operations
|
|
5
|
+
Author-email: fwkrumm <fwkrumm@github.com>
|
|
6
|
+
Maintainer-email: fwkrumm <fwkrumm@github.com>
|
|
7
|
+
Project-URL: Homepage, https://github.com/fwkrumm/pymembar
|
|
8
|
+
Project-URL: Repository, https://github.com/fwkrumm/pymembar
|
|
9
|
+
Project-URL: Issues, https://github.com/fwkrumm/pymembar/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/fwkrumm/pymembar/blob/master/README.md
|
|
11
|
+
Keywords: memory-barriers,concurrency,low-level,synchronization,threading
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Operating System :: MacOS
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: C
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: System :: Hardware
|
|
21
|
+
Classifier: Topic :: System :: Operating System
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE.txt
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# Python Memory Barrier (pymembar)
|
|
29
|
+
|
|
30
|
+
Memory barrier utilities for Python - provides low-level memory ordering primitives for concurrent programming. Usually you would not need this in Python due to GIL and generally strong memory ordering on x86/x86_64. However, on weakly-ordered architectures like ARM, memory barriers can be useful for ensuring correct visibility and ordering of memory operations when for example working with shared memory, named semaphores, or lock-free data structures.
|
|
31
|
+
|
|
32
|
+
I used AI (GitHub Copilot) to help generate parts of this README, documentation strings, parts of the core code, the tests, and some configuration files. Please report any inaccuracies or errors you may find.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## Overview
|
|
36
|
+
|
|
37
|
+
This package provides Python bindings for memory barrier operations, ensuring that memory operations are visible to other processes and threads in the correct order. Memory barriers do not provide synchronization themselves, but rather control the visibility and ordering of memory operations across CPU cores and processes.
|
|
38
|
+
|
|
39
|
+
The package includes three core functions:
|
|
40
|
+
|
|
41
|
+
- `wmb()` - Write memory barrier
|
|
42
|
+
- `rmb()` - Read memory barrier
|
|
43
|
+
- `fence()` - Full memory fence
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install pymembar
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### Basic Usage
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import membar
|
|
57
|
+
|
|
58
|
+
# Write memory barrier - ensures all write operations before this point
|
|
59
|
+
# are visible to other processes/threads before any writes after this point
|
|
60
|
+
membar.wmb()
|
|
61
|
+
|
|
62
|
+
# Read memory barrier - ensures all read operations before this point
|
|
63
|
+
# complete before any read operations after this point
|
|
64
|
+
membar.rmb()
|
|
65
|
+
|
|
66
|
+
# Full memory fence - ensures all memory operations before this point
|
|
67
|
+
# are visible to other processes/threads before any operations after this point
|
|
68
|
+
membar.fence()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Logging Support
|
|
72
|
+
|
|
73
|
+
You can enable optional logging to see which memory barrier implementation is being used at runtime. This is useful for debugging and understanding which underlying mechanism (C11 atomics, MSVC, GNU atomics, BSD, or compiler barrier) is executing on your platform.
|
|
74
|
+
|
|
75
|
+
**⚠️ Performance Warning:** Enabling logging adds overhead to every memory barrier call (callback check and function call overhead). This can significantly impact performance in tight loops or performance-critical code paths. Logging should primarily be used for debugging and development, and should be disabled (`set_log_callback(None)`) in production code where performance is critical.
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import membar
|
|
79
|
+
|
|
80
|
+
# Enable logging with a custom callback
|
|
81
|
+
def my_logger(message):
|
|
82
|
+
print(f"[MEMBAR] {message}")
|
|
83
|
+
|
|
84
|
+
membar.set_log_callback(my_logger)
|
|
85
|
+
|
|
86
|
+
# Now all barrier calls will log their implementation
|
|
87
|
+
membar.wmb() # Logs: "wmb: using C11 atomic_thread_fence(memory_order_release)"
|
|
88
|
+
membar.fence() # Logs: "fence: using C11 atomic_thread_fence(memory_order_seq_cst)"
|
|
89
|
+
|
|
90
|
+
# You can also use print directly
|
|
91
|
+
membar.set_log_callback(print)
|
|
92
|
+
|
|
93
|
+
# Or integrate with Python's logging module
|
|
94
|
+
import logging
|
|
95
|
+
logging.basicConfig(level=logging.INFO)
|
|
96
|
+
logger = logging.getLogger(__name__)
|
|
97
|
+
membar.set_log_callback(logger.info)
|
|
98
|
+
|
|
99
|
+
# Disable logging by passing None
|
|
100
|
+
membar.set_log_callback(None)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## When Are Memory Barriers Needed?
|
|
104
|
+
|
|
105
|
+
Memory barriers are primarily needed on weakly-ordered CPU architectures like ARM, where the processor may reorder memory operations for performance optimization. On x86/x86_64 architectures, the strong memory ordering model means that memory barriers are often not strictly necessary for most use cases, as the hardware already provides strong ordering guarantees.
|
|
106
|
+
|
|
107
|
+
However, memory barriers can still be useful on x86 in specific scenarios:
|
|
108
|
+
- When interfacing with memory-mapped I/O
|
|
109
|
+
- In lock-free programming with specific compiler optimizations
|
|
110
|
+
- When precise ordering is critical for correctness
|
|
111
|
+
|
|
112
|
+
**Note:** Most Python applications will not need memory barriers due to the Global Interpreter Lock (GIL) and Python's threading model.
|
|
113
|
+
|
|
114
|
+
## Requirements
|
|
115
|
+
|
|
116
|
+
- Python 3.10+
|
|
117
|
+
- Compatible with Windows, Linux, and macOS
|
|
118
|
+
|
|
119
|
+
## Contributing
|
|
120
|
+
|
|
121
|
+
I am not a C expert and would be happy to receive any constructive feedback, suggestions, or contributions to improve this library. Feel free to open issues or submit pull requests on the [GitHub repository](https://github.com/fwkrumm/pymembar).
|
|
122
|
+
|
|
123
|
+
## Disclaimer
|
|
124
|
+
|
|
125
|
+
Parts of the core code, the tests, this README, and documentation strings were generated with AI assistance.
|
|
126
|
+
|
|
127
|
+
## Release history
|
|
128
|
+
|
|
129
|
+
- 0.0.1 - Initial release
|
|
130
|
+
- 0.0.2 - Added ARM build support
|
|
131
|
+
- 0.0.3 - Added logging support and multiple synchronization implementations
|
|
132
|
+
- 0.0.4 - Improved logging thread safety and documentation
|
|
133
|
+
- 0.1.0 - Dropped EOL Python versions (3.8, 3.9); minimum is now Python 3.10
|
|
134
|
+
- 0.1.1 - Removed minor-version Python classifiers; Python 3.10+ remains required.
|
|
135
|
+
- 0.1.2 - Added Python 3.15 wheel and source distribution.
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
## TODOs
|
|
139
|
+
- Is it possible to write tests for the memory barrier core functionality?
|
pymembar-0.1.2/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Python Memory Barrier (pymembar)
|
|
2
|
+
|
|
3
|
+
Memory barrier utilities for Python - provides low-level memory ordering primitives for concurrent programming. Usually you would not need this in Python due to GIL and generally strong memory ordering on x86/x86_64. However, on weakly-ordered architectures like ARM, memory barriers can be useful for ensuring correct visibility and ordering of memory operations when for example working with shared memory, named semaphores, or lock-free data structures.
|
|
4
|
+
|
|
5
|
+
I used AI (GitHub Copilot) to help generate parts of this README, documentation strings, parts of the core code, the tests, and some configuration files. Please report any inaccuracies or errors you may find.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
This package provides Python bindings for memory barrier operations, ensuring that memory operations are visible to other processes and threads in the correct order. Memory barriers do not provide synchronization themselves, but rather control the visibility and ordering of memory operations across CPU cores and processes.
|
|
11
|
+
|
|
12
|
+
The package includes three core functions:
|
|
13
|
+
|
|
14
|
+
- `wmb()` - Write memory barrier
|
|
15
|
+
- `rmb()` - Read memory barrier
|
|
16
|
+
- `fence()` - Full memory fence
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install pymembar
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Basic Usage
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import membar
|
|
30
|
+
|
|
31
|
+
# Write memory barrier - ensures all write operations before this point
|
|
32
|
+
# are visible to other processes/threads before any writes after this point
|
|
33
|
+
membar.wmb()
|
|
34
|
+
|
|
35
|
+
# Read memory barrier - ensures all read operations before this point
|
|
36
|
+
# complete before any read operations after this point
|
|
37
|
+
membar.rmb()
|
|
38
|
+
|
|
39
|
+
# Full memory fence - ensures all memory operations before this point
|
|
40
|
+
# are visible to other processes/threads before any operations after this point
|
|
41
|
+
membar.fence()
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Logging Support
|
|
45
|
+
|
|
46
|
+
You can enable optional logging to see which memory barrier implementation is being used at runtime. This is useful for debugging and understanding which underlying mechanism (C11 atomics, MSVC, GNU atomics, BSD, or compiler barrier) is executing on your platform.
|
|
47
|
+
|
|
48
|
+
**⚠️ Performance Warning:** Enabling logging adds overhead to every memory barrier call (callback check and function call overhead). This can significantly impact performance in tight loops or performance-critical code paths. Logging should primarily be used for debugging and development, and should be disabled (`set_log_callback(None)`) in production code where performance is critical.
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
import membar
|
|
52
|
+
|
|
53
|
+
# Enable logging with a custom callback
|
|
54
|
+
def my_logger(message):
|
|
55
|
+
print(f"[MEMBAR] {message}")
|
|
56
|
+
|
|
57
|
+
membar.set_log_callback(my_logger)
|
|
58
|
+
|
|
59
|
+
# Now all barrier calls will log their implementation
|
|
60
|
+
membar.wmb() # Logs: "wmb: using C11 atomic_thread_fence(memory_order_release)"
|
|
61
|
+
membar.fence() # Logs: "fence: using C11 atomic_thread_fence(memory_order_seq_cst)"
|
|
62
|
+
|
|
63
|
+
# You can also use print directly
|
|
64
|
+
membar.set_log_callback(print)
|
|
65
|
+
|
|
66
|
+
# Or integrate with Python's logging module
|
|
67
|
+
import logging
|
|
68
|
+
logging.basicConfig(level=logging.INFO)
|
|
69
|
+
logger = logging.getLogger(__name__)
|
|
70
|
+
membar.set_log_callback(logger.info)
|
|
71
|
+
|
|
72
|
+
# Disable logging by passing None
|
|
73
|
+
membar.set_log_callback(None)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## When Are Memory Barriers Needed?
|
|
77
|
+
|
|
78
|
+
Memory barriers are primarily needed on weakly-ordered CPU architectures like ARM, where the processor may reorder memory operations for performance optimization. On x86/x86_64 architectures, the strong memory ordering model means that memory barriers are often not strictly necessary for most use cases, as the hardware already provides strong ordering guarantees.
|
|
79
|
+
|
|
80
|
+
However, memory barriers can still be useful on x86 in specific scenarios:
|
|
81
|
+
- When interfacing with memory-mapped I/O
|
|
82
|
+
- In lock-free programming with specific compiler optimizations
|
|
83
|
+
- When precise ordering is critical for correctness
|
|
84
|
+
|
|
85
|
+
**Note:** Most Python applications will not need memory barriers due to the Global Interpreter Lock (GIL) and Python's threading model.
|
|
86
|
+
|
|
87
|
+
## Requirements
|
|
88
|
+
|
|
89
|
+
- Python 3.10+
|
|
90
|
+
- Compatible with Windows, Linux, and macOS
|
|
91
|
+
|
|
92
|
+
## Contributing
|
|
93
|
+
|
|
94
|
+
I am not a C expert and would be happy to receive any constructive feedback, suggestions, or contributions to improve this library. Feel free to open issues or submit pull requests on the [GitHub repository](https://github.com/fwkrumm/pymembar).
|
|
95
|
+
|
|
96
|
+
## Disclaimer
|
|
97
|
+
|
|
98
|
+
Parts of the core code, the tests, this README, and documentation strings were generated with AI assistance.
|
|
99
|
+
|
|
100
|
+
## Release history
|
|
101
|
+
|
|
102
|
+
- 0.0.1 - Initial release
|
|
103
|
+
- 0.0.2 - Added ARM build support
|
|
104
|
+
- 0.0.3 - Added logging support and multiple synchronization implementations
|
|
105
|
+
- 0.0.4 - Improved logging thread safety and documentation
|
|
106
|
+
- 0.1.0 - Dropped EOL Python versions (3.8, 3.9); minimum is now Python 3.10
|
|
107
|
+
- 0.1.1 - Removed minor-version Python classifiers; Python 3.10+ remains required.
|
|
108
|
+
- 0.1.2 - Added Python 3.15 wheel and source distribution.
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
## TODOs
|
|
112
|
+
- Is it possible to write tests for the memory barrier core functionality?
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// membar.h
|
|
2
|
+
#pragma once
|
|
3
|
+
|
|
4
|
+
#ifdef _WIN32
|
|
5
|
+
#define MEMBAR_EXPORT __declspec(dllexport)
|
|
6
|
+
#else
|
|
7
|
+
#define MEMBAR_EXPORT
|
|
8
|
+
#endif
|
|
9
|
+
|
|
10
|
+
#ifdef __cplusplus
|
|
11
|
+
extern "C" {
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* write memory barrier
|
|
16
|
+
* ensures that all previous memory writes are visible before any subsequent writes
|
|
17
|
+
*/
|
|
18
|
+
MEMBAR_EXPORT void membar_wmb(void);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* read memory barrier
|
|
22
|
+
* ensures that all previous memory reads are completed before any subsequent reads
|
|
23
|
+
*/
|
|
24
|
+
MEMBAR_EXPORT void membar_rmb(void);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* full fence (both read and write)
|
|
28
|
+
* provides sequential consistency across memory operations
|
|
29
|
+
*/
|
|
30
|
+
MEMBAR_EXPORT void membar_fence(void);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* logging callback function type
|
|
34
|
+
* @param message - the log message to output
|
|
35
|
+
*/
|
|
36
|
+
typedef void (*membar_log_callback)(const char* message);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* set optional logging callback
|
|
40
|
+
* @param callback - function to call for logging, or NULL to disable logging
|
|
41
|
+
*/
|
|
42
|
+
MEMBAR_EXPORT void membar_set_log_callback(membar_log_callback callback);
|
|
43
|
+
|
|
44
|
+
#ifdef __cplusplus
|
|
45
|
+
}
|
|
46
|
+
#endif
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Memory barrier utilities: wmb, rmb, and fence operations."""
|
|
2
|
+
# pylint: disable=duplicate-code
|
|
3
|
+
try:
|
|
4
|
+
from ._membar import wmb, rmb, fence, set_log_callback # Import from private C extension
|
|
5
|
+
__all__ = ['wmb', 'rmb', 'fence', 'set_log_callback']
|
|
6
|
+
except ImportError as e:
|
|
7
|
+
raise ImportError(f"Could not import C extension module: {e}") from e
|
|
8
|
+
|
|
9
|
+
# do NOT alter the following line in any way EXCEPT changing
|
|
10
|
+
# the version number. no comments, no rename, whatsoever
|
|
11
|
+
__version__ = "0.1.2"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type stubs for membar module - Memory barrier utilities for Python
|
|
3
|
+
"""
|
|
4
|
+
from typing import Optional, Callable
|
|
5
|
+
|
|
6
|
+
def wmb() -> None:
|
|
7
|
+
"""
|
|
8
|
+
Write memory barrier.
|
|
9
|
+
|
|
10
|
+
Ensures that all write operations issued before this barrier
|
|
11
|
+
are completed before any write operations issued after this barrier.
|
|
12
|
+
"""
|
|
13
|
+
...
|
|
14
|
+
|
|
15
|
+
def rmb() -> None:
|
|
16
|
+
"""
|
|
17
|
+
Read memory barrier.
|
|
18
|
+
|
|
19
|
+
Ensures that all read operations issued before this barrier
|
|
20
|
+
are completed before any read operations issued after this barrier.
|
|
21
|
+
"""
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
def fence() -> None:
|
|
25
|
+
"""
|
|
26
|
+
Full memory fence.
|
|
27
|
+
|
|
28
|
+
Ensures that all memory operations (both reads and writes) issued before
|
|
29
|
+
this barrier are completed before any memory operations issued after this barrier.
|
|
30
|
+
"""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
def set_log_callback(callback: Optional[Callable[[str], None]]) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Set optional logging callback.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
callback: A callable that takes a string message, or None to disable logging.
|
|
39
|
+
The callback will be invoked whenever a memory barrier function is called,
|
|
40
|
+
with information about which implementation is being used.
|
|
41
|
+
|
|
42
|
+
Example:
|
|
43
|
+
>>> import membar
|
|
44
|
+
>>> membar.set_log_callback(print)
|
|
45
|
+
>>> membar.wmb() # will log which implementation is used
|
|
46
|
+
>>> membar.set_log_callback(None) # disable logging
|
|
47
|
+
|
|
48
|
+
Or use a custom logger:
|
|
49
|
+
>>> import logging
|
|
50
|
+
>>> logger = logging.getLogger("membar_logger")
|
|
51
|
+
>>> membar.set_log_callback(logger.info) # Use logger.info (can also use .debug, .warning, etc.)
|
|
52
|
+
>>> membar.rmb() # logs via the logger
|
|
53
|
+
>>> membar.set_log_callback(None) # disable logging
|
|
54
|
+
"""
|
|
55
|
+
...
|
|
56
|
+
|
|
57
|
+
__all__ = ['wmb', 'rmb', 'fence', 'set_log_callback']
|
|
File without changes
|