Go to file
Marc Siegel 4518e6fdad Fix ConditionVariable#signal to only post if semaphore has waiters
This fixes a bug where calls to #signal would end up "over-posting"
the semaphore, causing subsequent waits to return immediately until
the semaphore value is back down to zero.
2013-12-27 15:15:07 -05:00
ext/helper Don't include compiled extension in gem; configure extconf.rb to compile and install into the correct location. Fixes #4. 2013-02-19 13:56:53 -06:00
lib Fix ConditionVariable#signal to only post if semaphore has waiters 2013-12-27 15:15:07 -05:00
spec Fix ConditionVariable#signal to only post if semaphore has waiters 2013-12-27 15:15:07 -05:00
.gitignore Add target dir to .gitignore. 2012-03-24 13:35:08 -05:00
.travis.yml Add ruby 2.0.0 to travis config. 2013-02-21 13:09:08 -06:00
COPYING Initial commit. 2011-12-11 21:39:55 -06:00
ChangeLog Initial commit. 2011-12-11 21:39:55 -06:00
Gemfile Initial commit. 2011-12-11 21:39:55 -06:00
README.rdoc Rdoc formatting. 2012-03-04 10:29:43 -06:00
Rakefile Don't include compiled extension in gem; configure extconf.rb to compile and install into the correct location. Fixes #4. 2013-02-19 13:56:53 -06:00
VERSION Version bump to 0.1.9a 2013-12-26 22:39:44 -06:00
process_shared.gemspec Don't include compiled extension in gem; configure extconf.rb to compile and install into the correct location. Fixes #4. 2013-02-19 13:56:53 -06:00

README.rdoc

== Description

Concurrency primitives that may be used in a cross-process way to
coordinate share memory between processes.

FFI is used to access POSIX semaphore on Linux or Mach semaphores on
Mac.  Atop these semaphores are implemented ProcessShared::Semaphore,
ProcessShared::Mutex.  POSIX shared memory is used to implement
ProcessShared::SharedMemory.

On Linux, POSIX semaphores support <tt>sem_timedwait()</tt> which can wait on
a semaphore but stop waiting after a timeout.

Mac OS X's implementation of POSIX semaphores does not support
timeouts.  But, the Mach layer in Mac OS X has its own semaphores that
do support timeouts.  Thus, process_shared implements a moderate
subset of the Mach API, which is quite a bit different from POSIX.
Namely, semaphores created in one process are not available in child
processes created via <tt>fork()</tt>.  Mach does provide the means to copy
capabilities between tasks (Mach equivalent to processes).
process_shared overrides Ruby's <tt>fork</tt> methods so that semaphores are
copied from parent to child to emulate the POSIX behavior.

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)}"

== 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']

== Todo

* Test ConditionVariable
* Implement optional override of core Thread/Mutex classes
* Extend to win32?  (See Python's processing library)
* Add finalizer to Mutex? (finalizer on Semaphore objects may be enough) or a method to
  explicitly close and release resources?
* Test semantics of crashing processes who still hold locks, etc.
* Is SharedArray with Enumerable mixing sufficient Array-like interface?