Concurrent Shared Memory

OS-specific details

Windows

Not supported (will not compile).

MacOS

  • SharedMemory#size= can only be called once per object.
  • SharedMemory#size=(n) rounds up to the nearest multiple of the system page size (usually 4KiB).
  • Region.map will raise Errno::EINVAL if the shared memory object is not large enough.

Linux

  • SharedMemory#size= can be called more than once per object.
  • SharedMemory#size=(n) will not round, and #size will report the value set.
  • Region.map will succeed regardless of the shared memory object's size, but calling Region#read or Region#write will cause a bus error (and crash the program) if the read/write is out of bounds of the shared memory object.

WARNING

This library does not guarentee memory safety - it assumes you know what you're doing. If you are uncomfortable using the underlying constructs directly, you probably shouldn't use this library. If you're not careful, things will go wrong.

  1. Never allocate multiple objects using the same or overlapping regions of the same shared memory space. The library will not stop you, but doing this will likely cause memory faults.
  2. Avoid using Region#as_*ptr methods. The returned pointer objects do not retain a reference to the region. If the region is garbage collected, it will be unmapped, and subsequent pointer accesses will likely cause memory faults.
   shm = ConcurrentSHM::SharedMemory.open("/foo/bar", 0600, mode: :anon)
   value = ConcurrentSHM::Region.map(shm, 0, 1).as_intptr
   GC.start
   value.read # => memory fault

In the above example, value.read will likely cause a crash - if the region value was created from has been garbage collected, value will point to unmapped memory, since regions are unmapped once they are collected.

Examples

shm = ConcurrentSHM::SharedMemory.open("/foo/bar", 0600, mode: :anon)
ch = ConcurrentSHM::Channel::SingleBuffered::Variable.new(shm, capacity: 200)

fork do
    loop do
        s = ch.recv
        puts "received! #{s.inspect}"
    end
end

STDIN.each_line do |l|
  ch.send(l)
end