Devo eseguire il fork di un programma server come processo secondario "C" per consentire la corretta comunicazione tra processi?

2

Vorrei implementare la comunicazione tra processi tra un client di registrazione C # 1 di Ubuntu Linux 15.10 mono 4.1.2 e un server video C # di Ubuntu Linux 15.10 mono 4.1.2 utilizzando una classe di Cex e classe di evento C ++ che utilizza pthreads, shm_open e mmap.

Il client del registratore e il server video risiedono sulla stessa macchina Ubuntu Linux. Inoltre, un client Windows 7 C # in esecuzione su una macchina separata comunica con un programma client-server Ubuntu Linux 15.10 C # utilizzando socket TCP / IP.

In Programmazione avanzata nella seconda edizione dell'ambiente UNIX di W. Richard Stevens e Stephen A. Rago, ho letto la pagina 489 che afferma

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

Ho bisogno di sapere se devo biforcare il programma del video server come un processo secondario "C" in modo che la comunicazione tra processi avvenga tramite il cast del valore di ritorno di mmap su un puntatore pthread_mutex_t. Voglio condividere la variabile pthread mutex e pthread condition tra il processo del server video e il processo client del registratore.

Ho confuso le discussioni con i processi?

Boost ha scritto un interessante articolo su questo argomento che ho estratto un estratto da mostrato di seguito,

link

Limitazioni durante la costruzione di oggetti in regioni mappate Puntatori offset invece di puntatori non elaborati

Quando due processi creano una regione mappata dello stesso oggetto mappabile, due processi possono comunicare scrivendo e leggendo quella memoria. Un processo potrebbe costruire un oggetto C ++ in quella memoria in modo che il secondo processo possa utilizzarlo. Tuttavia, una regione mappata condivisa da più processi, non può contenere alcun oggetto C ++, perché non tutte le classi sono pronte per essere un oggetto condiviso dal processo, specialmente se la regione mappata è mappata in indirizzi diversi in ogni processo.

Quando si posizionano oggetti in una regione mappata e si esegue il mapping di quella regione in indirizzi diversi in ogni processo, i puntatori grezzi rappresentano un problema poiché sono validi solo per il processo che li ha posizionati lì. Per risolvere questo problema, Boost.Interprocess offre uno speciale puntatore intelligente che può essere utilizzato al posto di un puntatore non elaborato. Pertanto, le classi utente contenenti puntatori non elaborati (o puntatori intelligenti Boost, che possiedono internamente un puntatore raw) non possono essere collocate in modo sicuro in una regione mappata condivisa dal processo. Questi puntatori devono essere sostituiti con puntatori offset e questi puntatori devono puntare solo agli oggetti posizionati nella stessa regione mappata se si desidera utilizzare questi oggetti condivisi da processi diversi.

Ovviamente, un puntatore posizionato in una regione mappata condivisa tra processi dovrebbe puntare solo a un oggetto di quella regione mappata. In caso contrario, il puntatore farebbe riferimento a un indirizzo in cui è valido un solo processo e altri processi potrebbero bloccarsi durante l'accesso a tale indirizzo.

Basile Starynkevitch ha scritto il 21 aprile 2016, "Il punto non è usare il mutex pthread e le variabili di condizione come il tuo sogno. Sii creativo anche ...", in risposta alla mia domanda su come emulare un evento di Windows in Linux.
      Così, ho trovato il pdf, Implementare le variabili di condizione con semafori, link , scritto dal ricercatore di Microsoft, Andrew D Birrell. Sotto . Ho mostrato un estratto di questo articolo,

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();
 }
}

Potrei sfruttare la ricerca di Andrew D. Birrell per emulare un evento di Windows con una classe come questa:

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

    
posta Frank 15.04.2016 - 12:38
fonte

3 risposte

1

Non usare i mutex Pthread per sincronizzare tra processi , almeno su Linux. (Non sono sicuro che Linux stia implementando pthread_mutexattr_setpshared correttamente ed efficientemente, almeno non in GNU glibc 2.21 ).

Usa semafori POSIX, vedi sem_overview (7) . Oppure considera il eventfd (2) specifico per Linux probabilmente con poll(2) & leggi (2) & scrivi (2) . Entrambi (semafori e eventfd -s) sono meccanismi di sincronizzazione alternativi (al mutex tra processi ).

Potresti anche studiare il codice sorgente della tua implementazione C # (sia Mono che Microsoft CLR sono oggi software libero). E potresti anche usare strace (1) o ltrace(1) per capire che cosa sta facendo il tuo programma C #.

Il punto è che non userai il mutex pthread & condvar come sogni. Devi essere creativo. Se utilizzi eventfd , potresti avere qualche thread aggiuntivo che lo esegue il polling e quindi trasmettere un condvar ... Se utilizzi i semafori, anche tu essere creativo ...

    
risposta data 19.04.2016 - 21:46
fonte
2

pthread_mutex_t non è progettato per funzionare in modo incrociato. È stato creato partendo dal presupposto che tutti i thread che lo utilizzano abbiano lo stesso spazio di indirizzamento.

Esistono tuttavia altre opzioni per condividere un mutex tra i processi. Come discusso nei commenti c'è futex(7) (che funzionerà su memoria condivisa) e sem_overview(7) (un semaforo con nome esplicito condiviso tra processi) entrambi funzioneranno in modo incrociato.

    
risposta data 15.04.2016 - 14:07
fonte
1

Se fossi in te, mi dimenticherei di usare entrambi i pthreads (che funzionano solo sui thread e non sui processi, e stai usando chiaramente più processi) o sulla memoria condivisa del tipo di cui stai parlando, come il trasferimento del maniglie tra i processi sarà un po 'un punto dolente quando si lavora in C #.

Una tecnica più semplice, che sta diventando sempre più frequente nei software Linux, è quella di creare un file in un'area di memoria temporanea (ad esempio / run / shm nelle distribuzioni Linux usando Filesystem Heirarchy Standard 3.0 o superiore, o / var / shm in sistemi più vecchi - Non uso Ubuntu ma posso vedere che la versione che stai usando è recente, e dato che si basa su Debian la cui versione attuale è basata su FHS 3.0, sospetto che dovresti usare / eseguire), e quindi aprire in entrambi i processi e utilizza mmap (o Mono.Unix.Native .Syscall.mmap nel tuo caso) per mappare il file nello spazio di memoria di entrambi i processi. Dopo averlo fatto, puoi condividere i dati semplicemente leggendo & scrivendo nell'area mappata.

Per l'esclusione reciproca, un processo simile può essere eseguito creando un file vuoto (tipicamente in / run / lock o / var / lock) e quindi usando lockf (anche entrambi in Mono.Unix.Native.Syscall ). In alternativa, puoi usare System.Threading.Semaphore costruito con un nome a livello di sistema .

    
risposta data 17.04.2016 - 18:18
fonte

Leggi altre domande sui tag