C – Forking a Server Program for Interprocess Communication

clinuxmultithreadingpointers

I would like to implement interprocess communication between an Ubuntu Linux 15.10 mono 4.1.2 C# recorder client and Ubuntu Linux 15.10 mono 4.1.2 C# video server using a C++ mutex class and C++ event class which harnesses pthreads, shm_open and mmap.

The recorder client and video server reside on the same Ubuntu Linux machine. In addition, a Windows 7 C# client running on a separate machine communicates with an Ubuntu Linux 15.10 C# client-server program using TCP/IP sockets.

In Advanced Programming in the UNIX Environment Second Edition by W. Richard Stevens and Stephen A. Rago, I read page 489 which states

A memory-mapped region is inherited by a child across a fork (since it's part of the parent's address space) , but for the same reason, is not inherited by the new program across an exec

I need to know if I have to fork the video server program as an "C" child process in order for interprocess communication to take place by casting the mmap return value to a pthread_mutex_t pointer . I want to share pthread mutex and pthread condition variable between the video server process and recorder client process.

Have I confused threads with processes?

Boost wrote an interesting article about this topic which I have extracted an excerpt from shown below,

http://www.boost.org/doc/libs/1_37_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_region_object_limitations

Limitations When Constructing Objects In Mapped Regions
Offset pointers instead of raw pointers

When two processes create a mapped region of the same mappable object, two processes can communicate writing and reading that memory. A process could construct a C++ object in that memory so that the second process can use it. However, a mapped region shared by multiple processes, can't hold any C++ object, because not every class is ready to be a process-shared object, specially, if the mapped region is mapped in different address in each process.

When placing objects in a mapped region and mapping that region in different address in every process, raw pointers are a problem since they are only valid for the process that placed them there. To solve this, Boost.Interprocess offers a special smart pointer that can be used instead of a raw pointer. So user classes containing raw pointers (or Boost smart pointers, that internally own a raw pointer) can't be safely placed in a process shared mapped region. These pointers must be replaced with offset pointers, and these pointers must point only to objects placed in the same mapped region if you want to use these shared objects from different processes.

Of course, a pointer placed in a mapped region shared between processes should only point to an object of that mapped region. Otherwise, the pointer would point to an address that it's only valid one process and other processes may crash when accessing to that address.

Basile Starynkevitch wrote on April 21 2016, "The point is won't use pthread mutex and condition variable like you dream of. Be creative too…" , in response to my question about how to emulate a Windows event in Linux.
So, I found the pdf, Implementing Condition Variables with Semaphores , http://research.microsoft.com/pubs/64242/implementingcvs.pdf, written by Microsoft researcher , Andrew D. Birrell . Below . I show an excerpt from this article ,

class Lock {
 Semaphore sm;
public Lock() { // constructor
 sm = new Semaphore(); sm.count =1; sm.limit = 1;
 }
public void Acquire() { sm.P(); }
public void Release() { sm.V(); }
}
You can come quite close to implementing a condition variable in a similar way:
class CV {
 Semaphore s;
 Lock m;
public CV(Lock m) { // Constructor
 this.m = m;
 s = new Semaphore(); s.count = 0; s.limit = 1;
 }
public void Wait() { // Pre-condition: this thread holds “m”
 m.Release();
 s.P();
 m.Acquire();
 }
public void Signal() {
 s.V();
 }
}

Could I harness Andrew D. Birrell's research to emulate a Windows event with a class like this:

class Event {
    Lock theLock;
    CV   theCV;
    bool triggered;

    Event* MakeEvent(string Name);
    Event* OpenEvent(string Name);
    void   CloseEvent(string Name, Event* anEvent);
    void   NukeEvent(string Name, Event* anEvent);
    void   SetEvent(Event* anEvent);
    void   ResetEvent(Event* anEvent);
    int    WaitForSingleObject(Event* anEvent, int millisecond);
}

?

Best Answer

Don't use Pthread mutexes to synchronize between processes, at least on Linux. (I am not sure that Linux is implementing pthread_mutexattr_setpshared correctly and efficiently, at least not in GNU glibc 2.21).

Use POSIX semaphores, see sem_overview(7). Or consider the Linux specific eventfd(2) probably with poll(2) & read(2) & write(2). Both (semaphores & eventfd-s) are alternative synchronization mechanisms (to mutex between processes).

You might also study the source code of your C# implementation (both Mono and Microsoft CLR are today free software). And you might also use strace(1) or ltrace(1) to understand what your C# program is doing.

The point is that you won't use pthread mutex & condvar like you dream of. You need to be creative. If using eventfd, you might have some additional thread polling it, and then broadcast a condvar ... If using semaphores, be creative too...

Related Topic