summaryrefslogtreecommitdiff
path: root/demo4
diff options
context:
space:
mode:
Diffstat (limited to 'demo4')
-rw-r--r--demo4/ReadMe.txt15
-rw-r--r--demo4/child.py21
-rw-r--r--demo4/parent.py46
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)