-
Notifications
You must be signed in to change notification settings - Fork 3
Usage
This is a sketch on how to use the buffer. Eventually we'll finish the full documentation, until then, this serves as a high-level on how to use this piece of software. The test cases and README documentation also serve as points of reference for syntax and behavior.
- a buffer object is a multi-channel, multi-process, multi-threaded dynamic allocator that allows the programmer to allocate an object, then create channels.
auto *buffer = ipc::buffer::initialize( "thehandle" );
where the programmer creates a buffer object that has the name "thehandle".
Each thread in each process should create a thread-local-storage (TLS) structure using this function and syntax:
ipc::buffer::get_tls_structure( buffer, thread_id );
Each thread should have it's own TLS, these are opened for each thread within each process.
The programmer creates a buffer object, then creates channels on top of that object, to create a single-producer, single consumer channel:
ipc::buffer::add_spsc_lf_channel( tls_producer,
channel_id_a )
Once channels are created, memory can be allocated in each process.
int *output =
(int*) ipc::buffer::allocate_record( tls_producer,
sizeof( int ),
channel_id_a );
This memory is allocated dynamically from the shared memory heap. Memory can be allocated in any order from any channel. A return of nullptr indicates that the buffer object is out of memory.
Each channel is a single-producer, single-consumer lock-free queue that can be multi-thread or multi-process.
Memory is sent and received from producers on a channel (e.g., channel_id_a). As an example, a producer would
while( ipc::buffer::send_record( tls_producer,
channel_id_a,
(void**)&output ) != ipc::tx_success );
The while
loop is needed because send_record can fail due to the lock_free point-to-point
connection. The send_record function sends data from the producer on a channel to the waiting
consumer on a channel. This is queued up within the buffer for the target to receive.
To receive data, a consumer would do:
while( ipc::buffer::receive_record( tls_consumer,
channel_id,
&record ) != ipc::tx_success );
where the consumer waits on data from the target channel and the given buffer registered with tls_consumer.
On either the producer or consumer side, freeing data back to the buffer
is accomplished via ipc::buffer::free_record( tls, record )
where tls is the thread local storage struct (TLS) and record is the
pointer returned by allocate_record.
Removing individual channels to free up internally allocated memory is preferred when channels are no longer being used by the calling thread. To do this, call
ipc::buffer::remove_channel( tls, channel_id );
where tls is a valid thread local storage object and channel_id is the specific channel you want to remove from this thread local storage object, and globally (note: channels are reference counted, which means if someone is using the channel, it won't be immediately deleted).
On thread exit, they should close the TLS structure that they've allocated. closing the TLS structure will deallocate any pre-allocations that the thread/channel combo has made on your behalf and it will also unlink all channels associated with this thread.
ipc::buffer::close_tls_structure( tls_consumer );
On exit (per process), the programmer should call the destruct function that will decrease the reference count on the shared memory buffer and if the reference count is zero then it will unlink and clear the shared memory region that backs this buffer.
ipc::buffer::destruct( buffer, "thehandle", true );