1# Python modules 2import time 3import hashlib 4 5# 3rd party modules 6import sysv_ipc 7 8# Utils for this demo 9import utils 10 11utils.say("Oooo 'ello, I'm Mrs. Premise!") 12 13params = utils.read_params() 14 15# Create the semaphore & shared memory. I read somewhere that semaphores 16# and shared memory have separate key spaces, so one can safely use the 17# same key for each. This seems to be true in my experience. 18 19# For purposes of simplicity, this demo code makes no allowance for the 20# failure of the semaphore or memory constructors. This is unrealistic 21# because one can never predict whether or not a given key will be available, 22# so your code must *always* be prepared for these functions to fail. 23 24semaphore = sysv_ipc.Semaphore(params["KEY"], sysv_ipc.IPC_CREX) 25memory = sysv_ipc.SharedMemory(params["KEY"], sysv_ipc.IPC_CREX) 26 27# I seed the shared memory with a random value which is the current time. 28what_i_wrote = time.asctime() 29s = what_i_wrote 30 31utils.write_to_memory(memory, what_i_wrote) 32 33for i in range(0, params["ITERATIONS"]): 34 utils.say("iteration %d" % i) 35 if not params["LIVE_DANGEROUSLY"]: 36 # Releasing the semaphore... 37 utils.say("releasing the semaphore") 38 semaphore.release() 39 # ...and wait for it to become available again. In real code it'd be 40 # wise to sleep briefly before calling .acquire() in order to be 41 # polite and give other processes an opportunity to grab the semaphore 42 # while it is free and thereby avoid starvation. But this code is meant 43 # to be a stress test that maximizes the opportunity for shared memory 44 # corruption, and politeness has no place in that. 45 utils.say("acquiring the semaphore...") 46 semaphore.acquire() 47 48 s = utils.read_from_memory(memory) 49 50 # I keep checking the shared memory until something new has been written. 51 while s == what_i_wrote: 52 if not params["LIVE_DANGEROUSLY"]: 53 utils.say("releasing the semaphore") 54 semaphore.release() 55 utils.say("acquiring the semaphore...") 56 semaphore.acquire() 57 58 # Once the call to .acquire() completes, I own the shared resource and 59 # I'm free to read from the memory. 60 s = utils.read_from_memory(memory) 61 62 # What I read must be the md5 of what I wrote or something's gone wrong. 63 what_i_wrote = what_i_wrote.encode() 64 65 try: 66 assert(s == hashlib.md5(what_i_wrote).hexdigest()) 67 except AssertionError: 68 raise AssertionError("Shared memory corruption after %d iterations." % i) 69 70 # MD5 the reply and write back to Mrs. Conclusion. 71 s = s.encode() 72 what_i_wrote = hashlib.md5(s).hexdigest() 73 utils.write_to_memory(memory, what_i_wrote) 74 75 76# Announce for one last time that the semaphore is free again so that 77# Mrs. Conclusion can exit. 78if not params["LIVE_DANGEROUSLY"]: 79 utils.say("Final release of the semaphore followed by a 5 second pause") 80 semaphore.release() 81 time.sleep(5) 82 # ...before beginning to wait until it is free again. 83 utils.say("Final acquisition of the semaphore") 84 semaphore.acquire() 85 86utils.say("Destroying semaphore and shared memory") 87# It'd be more natural to call memory.remove() and semaphore.remove() here, 88# but I'll use the module-level functions instead to demonstrate their use. 89sysv_ipc.remove_shared_memory(memory.id) 90sysv_ipc.remove_semaphore(semaphore.id) 91