2011-12-12 03:39:55 +00:00
|
|
|
== Description
|
|
|
|
|
|
|
|
Concurrency primitives that may be used in a cross-process way to
|
|
|
|
coordinate share memory between processes.
|
|
|
|
|
2011-12-12 04:21:42 +00:00
|
|
|
A small C library (libpsem) is compiled to provide portable access to
|
|
|
|
semaphores (based on http://pyprocessing.berlios.de/). This library
|
|
|
|
is then accessed using FFI to implement Ruby classes
|
|
|
|
ProcessShared::Semaphore, ProcessShared::BoundedSemaphore,
|
2011-12-12 03:39:55 +00:00
|
|
|
ProcessShared::Mutex, and ProcessShared::SharedMemory.
|
|
|
|
|
|
|
|
This is an incomplete work in progress.
|
|
|
|
|
|
|
|
== License
|
|
|
|
|
|
|
|
MIT
|
|
|
|
|
|
|
|
== Install
|
|
|
|
Install the gem with:
|
|
|
|
|
|
|
|
gem install process_shared
|
|
|
|
|
|
|
|
== Usage
|
|
|
|
|
|
|
|
require 'process_shared'
|
|
|
|
|
|
|
|
mutex = ProcessShared::Mutex.new
|
|
|
|
mem = ProcessShared::SharedMemory.new(:int) # extends FFI::Pointer
|
|
|
|
mem.put_int(0, 0)
|
|
|
|
|
|
|
|
pid1 = fork do
|
|
|
|
puts "in process 1 (#{Process.pid})"
|
|
|
|
10.times do
|
|
|
|
sleep 0.01
|
|
|
|
mutex.synchronize do
|
|
|
|
value = mem.get_int(0)
|
|
|
|
sleep 0.01
|
|
|
|
puts "process 1 (#{Process.pid}) incrementing"
|
|
|
|
mem.put_int(0, value + 1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
pid2 = fork do
|
|
|
|
puts "in process 2 (#{Process.pid})"
|
|
|
|
10.times do
|
|
|
|
sleep 0.01
|
|
|
|
mutex.synchronize do
|
|
|
|
value = mem.get_int(0)
|
|
|
|
sleep 0.01
|
|
|
|
puts "process 2 (#{Process.pid}) decrementing"
|
|
|
|
mem.put_int(0, value - 1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Process.wait(pid1)
|
|
|
|
Process.wait(pid2)
|
|
|
|
|
|
|
|
puts "value should be zero: #{mem.get_int(0)}"
|
|
|
|
|
2011-12-21 04:16:50 +00:00
|
|
|
== Transfer Objects Across Processes
|
|
|
|
|
|
|
|
# allocate a sufficient memory block
|
|
|
|
mem = ProcessShared::SharedMemory.new(1024)
|
|
|
|
|
|
|
|
# sub process can write (serialize) object to memory (with bounds checking)
|
|
|
|
pid = fork do
|
|
|
|
mem.write_object(['a', 'b'])
|
|
|
|
end
|
|
|
|
|
|
|
|
Process.wait(pid)
|
|
|
|
|
|
|
|
# parent process can read the object back (synchronizing access
|
|
|
|
# with a Mutex left as an excercie to reader)
|
|
|
|
|
|
|
|
mem.read_object.must_equal ['a', 'b']
|
|
|
|
|
2011-12-12 03:39:55 +00:00
|
|
|
== Todo
|
|
|
|
|
2011-12-17 17:07:57 +00:00
|
|
|
* Test ConditionVariable
|
2011-12-12 03:39:55 +00:00
|
|
|
* Implement optional override of core Thread/Mutex classes
|
|
|
|
* Extend libpsem to win32? (See Python's processing library)
|
|
|
|
* Break out tests that use PSem.getvalue() (which isn't supported on Mac OS X)
|
|
|
|
so that the test suite will pass
|
|
|
|
* Add finalizer to Mutex? (finalizer on Semaphore objects may be enough) or a method to
|
2011-12-17 17:07:57 +00:00
|
|
|
explicitly close and release resources?
|
|
|
|
* Test semantics of crashing processes who still hold locks, etc.
|
2011-12-21 04:16:50 +00:00
|
|
|
* Is SharedArray with Enumerable mixing sufficient Array-like interface?
|
2011-12-17 17:09:51 +00:00
|
|
|
* Remove bsem from libpsem as it is of little use and doesn't work on Mac OS X
|
|
|
|
* Possibly implement BoundedSemaphore with arbitrary bound (in Ruby
|
|
|
|
rather than relying on sem_getvalue()), but this is of little
|
|
|
|
utility beyond extra error checking..
|