If you find yourself in the following situation : you have to use separate processes because Python doesn't really support sending signals with multiple threads but you need some sort of mutual exclusion between these processes. Your additional Iron Python ingredient is that you don't really want to have dependencies on any external modules not shipped with Python that implement SysV IPC or shared objects (though this is probably the most correct solution).
If you're a Python programmer and not a C programmer, you may not realise that mmap can map memory anonymously as it's not mentioned in the help. In this case, anonymously means that it is not really backed by a file, but by system memory. This doesn't seem to be documented in the Python documenation, but will work with most any reasonable Unix system.
Here is a Half Baked Mutex based on anonymous shared memory. This version really is half baked, because it uses the "Bakery Algorithm" designed by Lamport (which Peter Chubb taught me about in distributed systems). It differs slightly though -- our maximum ticket number must be less than 256 because of interactions between the python mmap, which treats the mmaped area as a string and the ascii character set (via ord and chr). This means heavily contested locks will be a bit "jerky" as the system waits to free up a few slots before continuing. We have a smattering of calls to sleep to attempt to reduce busy waiting. The only other caveat is "hashing" the PID down to a 1024 byte array -- a collision would probably be fatal to the algorithm.
It's not perfect, but it might something like it might get you out of a bind.
import os import sys from time import sleep class HalfBakedMutex: def __init__(self): import mmap #C is an array of people waiting for a ticket self.C = mmap.mmap(-1, 1024, mmap.MAP_SHARED|mmap.MAP_ANONYMOUS) #N is list of tickets people are holding self.N = mmap.mmap(-1, 1024, mmap.MAP_SHARED|mmap.MAP_ANONYMOUS) def take_a_number(self): #pick a number to "see the baker" i = os.getpid() % 1024 #find current maximum number while True: #indicate we are currently getting a number self.C[i] = chr(1) max = 0 for j in range(1024): if (ord(self.N[j])) > max: max = ord(self.N[j]) #we can't have max > 256 as chr(256) will fail if (max + 1 < 256): break else: self.C[i] = chr(0) sleep(0.1) #take next maximum self.N[i] = chr(max + 1) self.C[i] = chr(0) def lock(self): #first, take a number to see the baker self.take_a_number() i = os.getpid() % 1024 for j in range(1024): #make sure the process isn't currently getting a ticket while ord(self.C[j]) == 1: sleep(0.1) continue # If process j has a ticket, i.e. # N[j] > 0 # AND either the process has a lower ticket, or the same # ticket and a lower PID, i.e. # (N[j],j) < (N[i],i) # wait for it to run while (ord(self.N[j]) > 0) and (ord(self.N[j]),j) < (ord(self.N[i]),i) : sleep(0.1) continue #if we made it here, it is our turn to run! return def unlock(self): i = os.getpid() % 1024 self.N[i] = chr(0) mut = HalfBakedMutex() os.fork() os.fork() # 4 processes os.fork() # 8 processes os.fork() # 16 processes os.fork() # 32 processes os.fork() # 64 processes while True: mut.lock() print(" ------ " + `os.getpid()` + " ------ ") mut.unlock()