Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
gh-82300: Add track parameter to shared memory#110778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes from14 commits
3be08b4f50812acbc843171384476bbfca6db79426db11894d44cb82c62cff0dcda10f63d21d7e990e419c593ba9ef1ff3e5fe67466acf903fdf625d65e3f8a97c6d317c07f513f3fb67c7f0e7765afb7a5848c18255e015d8911766db5b852053f8File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -36,7 +36,7 @@ or other communications requiring the serialization/deserialization and | ||
| copying of data. | ||
| .. class:: SharedMemory(name=None, create=False, size=0, track=True) | ||
pan324 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| Creates a new shared memory block or attaches to an existing shared | ||
| memory block. Each shared memory block is assigned a unique name. | ||
| @@ -64,26 +64,38 @@ copying of data. | ||
| memory block may be larger or equal to the size requested. When attaching | ||
| to an existing shared memory block, the ``size`` parameter is ignored. | ||
| *track*, when enabled, registers the shared memory block with a resource | ||
| tracker process. This process ensures proper cleanup of shared memory | ||
| blocks even when all other processes with access to the memory have failed | ||
| to do so (mainly due to being killed by signals). Unless a Python process | ||
| was created using any of the :mod:`multiprocessing` facilities (such as | ||
| :class:`multiprocessing.Process`), it will receive its own resource tracker | ||
| process when accessing shared memory with *track* enabled. This will cause | ||
| the shared memory to be deleted by the resource tracker of the first | ||
| process that terminates. To avoid this issue, users of :mod:`subprocess` or | ||
| standalone Python processes should set *track* to ``False`` when there is | ||
| already another process in place that does the bookkeeping. *track* has | ||
| an effect only on POSIX. Windows has its own tracking and does not use the | ||
| resource tracker. | ||
gpshead marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| .. versionchanged:: 3.13 Added *track* parameter. | ||
| .. method:: close() | ||
| Closes the file descriptor/handle to the shared memory from this | ||
| instance. :meth:`close()` should be called once access to the shared | ||
| memory block from this instance is no longer needed. Depending | ||
| on operating system, the underlying memory may or may not be freed | ||
| even if all handles to it have been closed. To ensure proper cleanup, | ||
| use the :meth:`unlink()` method. | ||
| .. method:: unlink() | ||
| Deletes the underlying shared memory block. This should be called only | ||
gpshead marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| once per shared memory block regardless of the number of handles to it. | ||
pan324 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| :meth:`unlink()` and :meth:`close()` can be called in any order, but | ||
| trying to access data inside a shared memory block after :meth:`unlink()` | ||
| may result in memory access errors, depending on platform. | ||
pan324 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| .. attribute:: buf | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -71,8 +71,9 @@ class SharedMemory: | ||
| _flags = os.O_RDWR | ||
| _mode = 0o600 | ||
| _prepend_leading_slash = True if _USE_POSIX else False | ||
| _track = True | ||
pan324 marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| def __init__(self, name=None, create=False, size=0, track=True): | ||
| if not size >= 0: | ||
| raise ValueError("'size' must be a positive integer") | ||
| if create: | ||
| @@ -82,6 +83,7 @@ def __init__(self, name=None, create=False, size=0): | ||
| if name is None and not self._flags & os.O_EXCL: | ||
| raise ValueError("'name' can only be None if create=True") | ||
| self._track = track | ||
| if _USE_POSIX: | ||
| # POSIX Shared Memory | ||
| @@ -116,8 +118,8 @@ def __init__(self, name=None, create=False, size=0): | ||
| except OSError: | ||
| self.unlink() | ||
| raise | ||
| if self._track: | ||
| resource_tracker.register(self._name, "shared_memory") | ||
| else: | ||
| @@ -239,9 +241,11 @@ def unlink(self): | ||
| In order to ensure proper cleanup of resources, unlink should be | ||
| called once (and only once) across all processes which have access | ||
| to the shared memory block.""" | ||
gpshead marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| if _USE_POSIX and self._name: | ||
| _posixshmem.shm_unlink(self._name) | ||
| if self._track: | ||
| resource_tracker.unregister(self._name, "shared_memory") | ||
| _encoding = "utf8" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -4440,6 +4440,31 @@ def test_shared_memory_cleaned_after_process_termination(self): | ||
| "resource_tracker: There appear to be 1 leaked " | ||
| "shared_memory objects to clean up at shutdown", err) | ||
| @unittest.skipIf(os.name != "posix", "resource_tracker is posix only") | ||
| def test_shared_memory_untracking(self): | ||
gpshead marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| # gh-82300: When a separate Python process accesses shared memory | ||
| # with track=False, it must not register with the resource tracker. | ||
gpshead marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| cmd = '''if 1: | ||
| import sys | ||
| from unittest.mock import Mock | ||
| from multiprocessing import resource_tracker | ||
| from multiprocessing.shared_memory import SharedMemory | ||
| resource_tracker.register = Mock(side_effect=AssertionError) | ||
| mem = SharedMemory(create=False, name=sys.argv[1], track=False) | ||
| mem.close() | ||
| ''' | ||
| mem = shared_memory.SharedMemory(create=True, size=10) | ||
| try: | ||
| *_, err = test.support.script_helper.assert_python_ok("-c", cmd, | ||
| mem.name) | ||
| self.assertEqual(err, b'') | ||
| finally: | ||
| mem.close() | ||
| try: | ||
| mem.unlink() | ||
| except OSError: | ||
gpshead marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| pass | ||
| # | ||
| # Test to verify that `Finalize` works. | ||
| # | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Add ``track`` parameter to:class:`multiprocessing.shared_memory.SharedMemory` that allows using shared memory blocks without having to register with the resource tracker. | ||
pan324 marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||