diff options
Diffstat (limited to 'demo4')
-rw-r--r-- | demo4/ReadMe.txt | 15 | ||||
-rw-r--r-- | demo4/child.py | 21 | ||||
-rw-r--r-- | demo4/parent.py | 46 |
3 files changed, 82 insertions, 0 deletions
diff --git a/demo4/ReadMe.txt b/demo4/ReadMe.txt new file mode 100644 index 0000000..25f73e9 --- /dev/null +++ b/demo4/ReadMe.txt @@ -0,0 +1,15 @@ +This demonstrates the use of a semaphore with a Python context manager (a +'with' statement). + +To run the demo, simply run `python parent.py`. It launches child.py. + +The programs parent.py and child.py share a semaphore; the latter acquires the +semaphore via a context manager. The child process deliberately kills itself via +an error about half the time (randomly) in order to demonstrate that the +context manager releases the semaphore regardless of whether or not the context +block is exited gracefully. + +Once the child releases the semaphore, the parent destroys it. + +The whole thing happens in less than 10 seconds. + diff --git a/demo4/child.py b/demo4/child.py new file mode 100644 index 0000000..cbceb37 --- /dev/null +++ b/demo4/child.py @@ -0,0 +1,21 @@ +import posix_ipc +import time +import sys +import random + +# The parent passes the semaphore's name to me. +name = sys.argv[1] + +print('Child: waiting to aquire semaphore ' + name) + +with posix_ipc.Semaphore(name) as sem: + print('Child: semaphore ' + sem.name + ' aquired; holding for 3 seconds.') + + # Flip a coin to determine whether or not to bail out of the context. + if random.randint(0, 1): + print("Child: raising ValueError to demonstrate unplanned context exit") + raise ValueError + + time.sleep(3) + + print('Child: gracefully exiting context (releasing the semaphore).') diff --git a/demo4/parent.py b/demo4/parent.py new file mode 100644 index 0000000..799a6e7 --- /dev/null +++ b/demo4/parent.py @@ -0,0 +1,46 @@ +import subprocess +import posix_ipc +import time +import os + +sem = posix_ipc.Semaphore(None, posix_ipc.O_CREX, initial_value = 1) +print("Parent: created semaphore {}.".format(sem.name)) + +sem.acquire() + +# Spawn a child that will wait on this semaphore. +path, _ = os.path.split(__file__) +print("Parent: spawning child process...") +subprocess.Popen(["python", os.path.join(path, 'child.py'), sem.name]) + +for i in range(3, 0, -1): + print("Parent: child process will acquire the semaphore in {} seconds...".format(i)) + time.sleep(1) + +sem.release() + +# Sleep for a second to give the child a chance to acquire the semaphore. +# This technique is a little sloppy because technically the child could still +# starve, but it's certainly sufficient for this demo. +time.sleep(1) + +# Wait for the child to release the semaphore. +print("Parent: waiting for the child to release the semaphore.") +sem.acquire() + +# Clean up. +print("Parent: destroying the semaphore.") +sem.release() +sem.unlink() + +msg = """ +By the time you're done reading this, the parent will have exited and so the +operating system will have destroyed the semaphore. You can prove that the +semaphore is gone by running this command and observing that it raises +posix_ipc.ExistentialError -- + + python -c "import posix_ipc; posix_ipc.Semaphore('{}')" + +""".format(sem.name) + +print(msg) |