diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-02-21 04:46:49 +0000 |
---|---|---|
committer | <> | 2014-08-04 21:38:17 +0000 |
commit | f3765db04b903b3671733e07cf1541a51966dd14 (patch) | |
tree | defcc3c47d9b8bd78b97dcc04ee779a758d37b1c /demo2 | |
download | posix-ipc-tarball-master.tar.gz |
Imported from /home/lorry/working-area/delta_python-packages_posix-ipc-tarball/posix_ipc-0.9.8.tar.gz.HEADposix_ipc-0.9.8master
Diffstat (limited to 'demo2')
-rw-r--r-- | demo2/ReadMe.txt | 41 | ||||
-rw-r--r-- | demo2/SampleIpcConversation.png | bin | 0 -> 11909 bytes | |||
-rwxr-xr-x | demo2/cleanup.py | 15 | ||||
-rw-r--r-- | demo2/conclusion.py | 65 | ||||
-rw-r--r-- | demo2/params.txt | 4 | ||||
-rw-r--r-- | demo2/premise.py | 75 | ||||
-rw-r--r-- | demo2/utils.py | 42 |
7 files changed, 242 insertions, 0 deletions
diff --git a/demo2/ReadMe.txt b/demo2/ReadMe.txt new file mode 100644 index 0000000..fda0ce2 --- /dev/null +++ b/demo2/ReadMe.txt @@ -0,0 +1,41 @@ +This demonstrates use of message queues via two applications named after +Mrs. Premise and Mrs. Conclusion of the Monty Python sketch. +http://www.youtube.com/watch?v=crIJvcWkVcs + +Like those two characters, these programs chat back and forth and the result +is a lot of nonsense. In this case, what the programs are saying isn't the +interesting part. What's interesting is how they're doing it. + +Mrs. Premise and Mrs. Conclusion (the programs, not the sketch characters) +communicate with POSIX message queues. + +Mrs. Premise starts things off by creating the queue and sending a random +string (the current time) to it. She then sits in a loop receiving whatever +message is on the queue. If it is the same message she wrote, she sends it +back to the queue. If it is a new message, it must be from Mrs. Conclusion. + +Meanwhile, Mrs. Conclusion is doing exactly the same thing, except that she +assumes Mrs. Premise will write the first message. + +When either of these programs receives a new message, they send back an +md5 hash of that message. This serves two purposes. First, it ensures that +subsequent messages are very different so that if a message somehow gets +corrupted (say by being partially overwritten by the next message), it will +not escape notice. Second, it ensures that corruption can be detected if +it happens, because Mrs. Premise and Mrs. Conclusion can calculate what the +other's response to their message should be. + +Since message queues manage all of the concurrency issues transparently, +Mrs. Premise and Mrs. Conclusion won't ever find their messages corrupted +no matter how many messages they exchange. You can experiment with this by +setting ITERATIONS in params.txt to a very large value. + +These programs are not meant as a demostration on how to make best use of a +message queue. In fact, they're very badly behaved because they poll the +queue as fast as possible -- they'll send your CPU usage right up to 100%. +Remember, they're trying as hard as they can to step one another so as to +expose any concurrency problems that might be present. + +Real code would want to sleep (or do something useful) in between calling +send() and receive(). + diff --git a/demo2/SampleIpcConversation.png b/demo2/SampleIpcConversation.png Binary files differnew file mode 100644 index 0000000..9d11e7a --- /dev/null +++ b/demo2/SampleIpcConversation.png diff --git a/demo2/cleanup.py b/demo2/cleanup.py new file mode 100755 index 0000000..04e21e5 --- /dev/null +++ b/demo2/cleanup.py @@ -0,0 +1,15 @@ +import posix_ipc +import utils + +params = utils.read_params() + +try: + posix_ipc.unlink_message_queue(params["MESSAGE_QUEUE_NAME"]) + s = "message queue %s removed" % params["MESSAGE_QUEUE_NAME"] + print (s) +except: + print ("queue doesn't need cleanup") + + + +print ("\nAll clean!") diff --git a/demo2/conclusion.py b/demo2/conclusion.py new file mode 100644 index 0000000..d857663 --- /dev/null +++ b/demo2/conclusion.py @@ -0,0 +1,65 @@ +# Python modules +import time +import sys +PY_MAJOR_VERSION = sys.version_info[0] +# hashlib is only available in Python >= 2.5. I still want to support +# older Pythons so I import md5 if hashlib is not available. Fortunately +# md5 can masquerade as hashlib for my purposes. +try: + import hashlib +except ImportError: + import md5 as hashlib + +# 3rd party modules +import posix_ipc + +# Utils for this demo +import utils + + +utils.say("Oooo 'ello, I'm Mrs. Conclusion!") + +params = utils.read_params() + +# Mrs. Premise has already created the message queue. I just need a handle +# to it. +mq = posix_ipc.MessageQueue(params["MESSAGE_QUEUE_NAME"]) + +what_i_sent = "" + +for i in range(0, params["ITERATIONS"]): + utils.say("iteration %d" % i) + + s, _ = mq.receive() + s = s.decode() + utils.say("Received %s" % s) + + while s == what_i_sent: + # Nothing new; give Mrs. Premise another chance to respond. + mq.send(s) + + s, _ = mq.receive() + s = s.decode() + utils.say("Received %s" % s) + + if what_i_sent: + if PY_MAJOR_VERSION > 2: + what_i_sent = what_i_sent.encode() + try: + assert(s == hashlib.md5(what_i_sent).hexdigest()) + except AssertionError: + utils.raise_error(AssertionError, + "Message corruption after %d iterations." % i) + #else: + # When what_i_sent is blank, this is the first message which + # I always accept without question. + + # MD5 the reply and write back to Mrs. Premise. + s = hashlib.md5(s.encode()).hexdigest() + utils.say("Sending %s" % s) + mq.send(s) + what_i_sent = s + + +utils.say("") +utils.say("%d iterations complete" % (i + 1)) diff --git a/demo2/params.txt b/demo2/params.txt new file mode 100644 index 0000000..e8fa277 --- /dev/null +++ b/demo2/params.txt @@ -0,0 +1,4 @@ +# These parameters control how Mrs. Premise and Mrs. Conclusion behave. + +ITERATIONS=1000 +MESSAGE_QUEUE_NAME=/my_message_queue diff --git a/demo2/premise.py b/demo2/premise.py new file mode 100644 index 0000000..9de9a09 --- /dev/null +++ b/demo2/premise.py @@ -0,0 +1,75 @@ +# Python modules +import time +import sys +PY_MAJOR_VERSION = sys.version_info[0] +# hashlib is only available in Python >= 2.5. I still want to support +# older Pythons so I import md5 if hashlib is not available. Fortunately +# md5 can masquerade as hashlib for my purposes. +try: + import hashlib +except ImportError: + import md5 as hashlib + +# 3rd party modules +import posix_ipc + +# Utils for this demo +import utils + + +utils.say("Oooo 'ello, I'm Mrs. Premise!") + +params = utils.read_params() + +# Create the message queue. +mq = posix_ipc.MessageQueue(params["MESSAGE_QUEUE_NAME"], posix_ipc.O_CREX) + +# The first message is a random string (the current time). +s = time.asctime() +utils.say("Sending %s" % s) +mq.send(s) +what_i_sent = s + +for i in range(0, params["ITERATIONS"]): + utils.say("iteration %d" % i) + + s, _ = mq.receive() + s = s.decode() + utils.say("Received %s" % s) + + # If the message is what I wrote, put it back on the queue. + while s == what_i_sent: + # Nothing new; give Mrs. Conclusion another chance to respond. + mq.send(s) + + s, _ = mq.receive() + s = s.decode() + utils.say("Received %s" % s) + + # What I read must be the md5 of what I wrote or something's + # gone wrong. + if PY_MAJOR_VERSION > 2: + what_i_sent = what_i_sent.encode() + + try: + assert(s == hashlib.md5(what_i_sent).hexdigest()) + except AssertionError: + utils.raise_error(AssertionError, + "Message corruption after %d iterations." % i) + + + # MD5 the reply and write back to Mrs. Conclusion. + s = hashlib.md5(s.encode()).hexdigest() + utils.say("Sending %s" % s) + mq.send(s) + what_i_sent = s + +utils.say("") +utils.say("%d iterations complete" % (i + 1)) + +utils.say("Destroying the message queue.") +mq.close() +# I could call simply mq.unlink() here but in order to demonstrate +# unlinking at the module level I'll do it that way. +posix_ipc.unlink_message_queue(params["MESSAGE_QUEUE_NAME"]) + diff --git a/demo2/utils.py b/demo2/utils.py new file mode 100644 index 0000000..31e2b05 --- /dev/null +++ b/demo2/utils.py @@ -0,0 +1,42 @@ +import time +import sys + +def say(s): + who = sys.argv[0] + if who.endswith(".py"): + who = who[:-3] + + s = "%s@%1.6f: %s" % (who, time.time(), s) + print (s) + + +def read_params(): + params = { } + + f = open("params.txt") + + for line in f: + line = line.strip() + if len(line): + if line.startswith('#'): + pass # comment in input, ignore + else: + name, value = line.split('=') + name = name.upper().strip() + + if name == "PERMISSIONS": + value = int(value, 8) + elif "NAME" in name: + # This is a string; leave it alone. + pass + else: + value = int(value) + + #print "name = %s, value = %d" % (name, value) + + params[name] = value + + f.close() + + return params + |