The example here shows two communicating processes that share a std::set. The first process fills the std::set and after it ends, the second iterates it through and lists imposed values to std::cout. Communication is synchronized using the standard mutex created via SYSV semaphores.
#include <mm.h>;
#include <cerrno>;
#include <cstdlib>
#include <iostream>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <shallocator/shset.h>
#include <shallocator/shmemory.h>
#include <shallocator/shstring.h>
#ifdef _SEM_SEMUN_UNDEFINED // see sys/sem.h
union semun {
int val ; // value for SETVAL
struct semid_ds * buf ; // buffer for IPC_STAT, IPC_SET
unsigned short * array ; // array for GETALL, SETALL
struct seminfo * __buf ; // buffer for IPC_INFO (Linux-specific)
};
#endif // _SEM_SEMUN_UNDEFINED
/**
* @short Holder for sem set id.
*/
class SemSetIdHolder_t {
public:
SemSetIdHolder_t ( int semsetid )
: semsetid ( semsetid ), hold ( true )
{
// check semaphore set id
if ( semsetid < 0 ) {
fprintf ( stderr , "semget: %s \n " , strerror ( errno ));
exit ( EXIT_FAILURE );
}
}
/**
* @short Deallocate semaphore set.
*/
~ SemSetIdHolder_t () {
if ( hold ) {
if ( semctl ( semsetid , 0 , IPC_RMID , 0 )) {
fprintf ( stderr , "semctl: %s \n " , strerror ( errno ));
exit ( EXIT_FAILURE );
}
}
}
operator int () const { return semsetid ;}
void release () { hold = false ;}
private:
int semsetid ;
bool hold ;
};
/**
* @short IPC semaphore mutex.
*/
class Mutex_t {
public:
/**
* @short Allocate new semaphore set.
*/
Mutex_t ()
: semsetid ( semget ( IPC_PRIVATE , 1 , IPC_CREAT | 0600 ))
{
// init semaphore
union semun arg ;
arg . val = 1 ;
if (( semctl ( semsetid , 0 , SETVAL , arg )) < 0 ) {
fprintf ( stderr , "semctl: %s \n " , strerror ( errno ));
exit ( EXIT_FAILURE );
}
}
void lock () {
// prepare structure for lock
struct sembuf op = { 0 , - 1 , SEM_UNDO };
// lock
if ( TEMP_FAILURE_RETRY ( semop ( semsetid , & op , 1 )) < 0 ) {
fprintf ( stderr , "semop: %s \n " , strerror ( errno ));
exit ( EXIT_FAILURE );
}
}
void unlock () {
// prepare structure for unlock
struct sembuf op = { 0 , + 1 , SEM_UNDO };
// unlock
if ( TEMP_FAILURE_RETRY ( semop ( semsetid , & op , 1 )) < 0 ) {
fprintf ( stderr , "semop: %s \n " , strerror ( errno ));
exit ( EXIT_FAILURE );
}
}
void release () { semsetid . release ();}
private:
Mutex_t ( const Mutex_t & );
Mutex_t & operator = ( const Mutex_t & );
SemSetIdHolder_t semsetid ;
};
/**
* @short Scope locker.
*/
class Lock_t {
public:
Lock_t ( Mutex_t & mutex ) : mutex ( mutex ) { mutex . lock ();}
~ Lock_t () { mutex . unlock ();}
private:
Lock_t ( const Lock_t & );
Lock_t & operator = ( const Lock_t & );
Mutex_t & mutex ;
};
/**
* @short Shared memmory pool holder.
*/
class SHPool_t {
public:
SHPool_t () : hold ( true ) { MM_create ( 1024 , 0 );}
~ SHPool_t () { if ( hold ) MM_destroy ();}
void release () { hold = false ;}
private:
SHPool_t ( const SHPool_t & );
SHPool_t & operator = ( const SHPool_t & );
bool hold ;
};
/**
* @short Usage example.
*/
void process ( SHAllocator :: shauto_ptr
< SHAllocator :: shset < SHAllocator :: shstring > > set ,
SHPool_t & pool , Mutex_t & mutex ) {
// if I'm first the set is empty
if ( set -> empty ()) {
// prepare some value
char buffer [ 1024 ];
snprintf ( buffer , sizeof ( buffer ), "%d" , getpid ());
// store value in set
set -> insert ( buffer );
// I shouldn't destroy set since other process is going to work with it
set . release ();
pool . release ();
mutex . release ();
} else {
// dump data to std::cout
for ( SHAllocator :: shset < SHAllocator :: shstring >:: const_iterator
iset = set -> begin (), eset = set -> end ();
iset != eset ; ++ iset ) {
std :: cout << getpid () << ": " << * iset << std :: endl ;
}
}
}
/**
* @short The main.
*/
int main ( int /*argc*/ , char ** /*argv*/ ) {
// allocate space for new allocator
SHPool_t pool ;
// get new mutex
Mutex_t mutex ;
// create new set container and store new pointer into auto_ptr
SHAllocator :: shauto_ptr < SHAllocator :: shset < SHAllocator :: shstring > > set
( new ( SHAllocator :: SHAlloc ) SHAllocator :: shset < SHAllocator :: shstring > ());
// do fork - don't care about errors ;-)
if ( ! fork ()) {
// in child lock mutex first
Lock_t lock ( mutex );
// try insert if child lock mutex first or dump data and destroy
// all resources
process ( set , pool , mutex );
} else {
// in parent lock mutex first too
Lock_t lock ( mutex );
// try insert if parent lock mutex first or dump data and destroy
// all resources
process ( set , pool , mutex );
}
return EXIT_SUCCESS ;
}