summaryrefslogtreecommitdiff
path: root/demo2
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-09-12 14:16:22 +0000
committer <>2014-10-24 11:04:40 +0000
commita77e3a63f004e6ee789fa05e4a5bbc333b1529f1 (patch)
treeefe8a68996c19b7b0765ebc689937721d1d99cf7 /demo2
downloadsysv-ipc-tarball-master.tar.gz
Imported from /home/lorry/working-area/delta_python-packages_sysv-ipc-tarball/sysv_ipc-0.6.8.tar.gz.HEADsysv_ipc-0.6.8master
Diffstat (limited to 'demo2')
-rw-r--r--demo2/ReadMe.txt41
-rw-r--r--demo2/SampleIpcConversation.pngbin0 -> 11909 bytes
-rwxr-xr-xdemo2/cleanup.py17
-rw-r--r--demo2/conclusion.py66
-rw-r--r--demo2/params.txt4
-rw-r--r--demo2/premise.py71
-rw-r--r--demo2/utils.py41
-rw-r--r--demo2/utils_for_2.py4
-rw-r--r--demo2/utils_for_3.py4
9 files changed, 248 insertions, 0 deletions
diff --git a/demo2/ReadMe.txt b/demo2/ReadMe.txt
new file mode 100644
index 0000000..871eba6
--- /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 Sys V 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 demonstration 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
new file mode 100644
index 0000000..9d11e7a
--- /dev/null
+++ b/demo2/SampleIpcConversation.png
Binary files differ
diff --git a/demo2/cleanup.py b/demo2/cleanup.py
new file mode 100755
index 0000000..3bc2aac
--- /dev/null
+++ b/demo2/cleanup.py
@@ -0,0 +1,17 @@
+import sysv_ipc
+import utils
+
+params = utils.read_params()
+
+
+try:
+ mq = sysv_ipc.MessageQueue(params["KEY"])
+ mq.remove()
+ s = "message queue %d removed" % params["KEY"]
+ print (s)
+except:
+ print ("message queue doesn't exist")
+
+
+
+print ("\nAll clean!") \ No newline at end of file
diff --git a/demo2/conclusion.py b/demo2/conclusion.py
new file mode 100644
index 0000000..3e1701a
--- /dev/null
+++ b/demo2/conclusion.py
@@ -0,0 +1,66 @@
+# 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 sysv_ipc
+
+# Utils for this demo
+import utils
+if PY_MAJOR_VERSION > 2:
+ import utils_for_3 as flex_utils
+else:
+ import utils_for_2 as flex_utils
+
+params = utils.read_params()
+
+# Mrs. Premise has already created the message queue. I just need a handle
+# to it.
+mq = sysv_ipc.MessageQueue(params["KEY"])
+
+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:
+ flex_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..e847cca
--- /dev/null
+++ b/demo2/params.txt
@@ -0,0 +1,4 @@
+# These parameters control how Mrs. Premise and Mrs. Conclusion behave.
+
+ITERATIONS=1000
+KEY=42
diff --git a/demo2/premise.py b/demo2/premise.py
new file mode 100644
index 0000000..942bba6
--- /dev/null
+++ b/demo2/premise.py
@@ -0,0 +1,71 @@
+# 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 sysv_ipc
+
+# Utils for this demo
+import utils
+if PY_MAJOR_VERSION > 2:
+ import utils_for_3 as flex_utils
+else:
+ import utils_for_2 as flex_utils
+
+utils.say("Oooo 'ello, I'm Mrs. Premise!")
+
+params = utils.read_params()
+
+# Create the message queue.
+mq = sysv_ipc.MessageQueue(params["KEY"], sysv_ipc.IPC_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:
+ flex_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.remove()
diff --git a/demo2/utils.py b/demo2/utils.py
new file mode 100644
index 0000000..0c66bee
--- /dev/null
+++ b/demo2/utils.py
@@ -0,0 +1,41 @@
+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", "r")
+
+ 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
+
diff --git a/demo2/utils_for_2.py b/demo2/utils_for_2.py
new file mode 100644
index 0000000..c00f914
--- /dev/null
+++ b/demo2/utils_for_2.py
@@ -0,0 +1,4 @@
+
+def raise_error(error, message):
+ raise error, message
+
diff --git a/demo2/utils_for_3.py b/demo2/utils_for_3.py
new file mode 100644
index 0000000..34155ae
--- /dev/null
+++ b/demo2/utils_for_3.py
@@ -0,0 +1,4 @@
+
+def raise_error(error, message):
+ raise error(message)
+