Ermöglicht der POSIX-Standard, dass ein gemeinsamer Speicherblock mit dem Namen eine Mutex- und Bedingungsvariable enthält?Bedingung Variable in Shared Memory - ist dieser Code POSIX-konform?
Wir haben versucht, eine Mutex- und eine Bedingungsvariable zu verwenden, um den Zugriff auf den benannten gemeinsamen Speicher durch zwei Prozesse auf einer LynuxWorks LynxOS-SE system (POSIX-konform) zu synchronisieren.
Ein gemeinsamer Speicherblock heißt "/sync"
und enthält die Mutex- und Bedingungsvariable, der andere ist "/data"
und enthält die tatsächlichen Daten, auf die wir den Zugriff synchronisieren.
Wir sehen Ausfälle von pthread_cond_signal()
wenn beide Prozesse ausführen nicht die mmap()
Anrufe in genau die gleiche Reihenfolge, oder wenn ein Prozess mmaps in einige andere Stück gemeinsam genutzten Speicher, bevor es den "/sync"
Speicher mmaps.
Dieses Beispiel-Code ist etwa so kurz wie ich es machen kann:
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <iostream>
#include <string>
using namespace std;
static const string shm_name_sync("/sync");
static const string shm_name_data("/data");
struct shared_memory_sync
{
pthread_mutex_t mutex;
pthread_cond_t condition;
};
struct shared_memory_data
{
int a;
int b;
};
//Create 2 shared memory objects
// - sync contains 2 shared synchronisation objects (mutex and condition)
// - data not important
void create()
{
// Create and map 'sync' shared memory
int fd_sync = shm_open(shm_name_sync.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
ftruncate(fd_sync, sizeof(shared_memory_sync));
void* addr_sync = mmap(0, sizeof(shared_memory_sync), PROT_READ|PROT_WRITE, MAP_SHARED, fd_sync, 0);
shared_memory_sync* p_sync = static_cast<shared_memory_sync*> (addr_sync);
// init the cond and mutex
pthread_condattr_t cond_attr;
pthread_condattr_init(&cond_attr);
pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&(p_sync->condition), &cond_attr);
pthread_condattr_destroy(&cond_attr);
pthread_mutexattr_t m_attr;
pthread_mutexattr_init(&m_attr);
pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&(p_sync->mutex), &m_attr);
pthread_mutexattr_destroy(&m_attr);
// Create the 'data' shared memory
int fd_data = shm_open(shm_name_data.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
ftruncate(fd_data, sizeof(shared_memory_data));
void* addr_data = mmap(0, sizeof(shared_memory_data), PROT_READ|PROT_WRITE, MAP_SHARED, fd_data, 0);
shared_memory_data* p_data = static_cast<shared_memory_data*> (addr_data);
// Run the second process while it sleeps here.
sleep(10);
int res = pthread_cond_signal(&(p_sync->condition));
assert(res==0); // <--- !!!THIS ASSERT WILL FAIL ON LYNXOS!!!
munmap(addr_sync, sizeof(shared_memory_sync));
shm_unlink(shm_name_sync.c_str());
munmap(addr_data, sizeof(shared_memory_data));
shm_unlink(shm_name_data.c_str());
}
//Open the same 2 shared memory objects but in reverse order
// - data
// - sync
void open()
{
sleep(2);
int fd_data = shm_open(shm_name_data.c_str(), O_RDWR, S_IRUSR|S_IWUSR);
void* addr_data = mmap(0, sizeof(shared_memory_data), PROT_READ|PROT_WRITE, MAP_SHARED, fd_data, 0);
shared_memory_data* p_data = static_cast<shared_memory_data*> (addr_data);
int fd_sync = shm_open(shm_name_sync.c_str(), O_RDWR, S_IRUSR|S_IWUSR);
void* addr_sync = mmap(0, sizeof(shared_memory_sync), PROT_READ|PROT_WRITE, MAP_SHARED, fd_sync, 0);
shared_memory_sync* p_sync = static_cast<shared_memory_sync*> (addr_sync);
// Wait on the condvar
pthread_mutex_lock(&(p_sync->mutex));
pthread_cond_wait(&(p_sync->condition), &(p_sync->mutex));
pthread_mutex_unlock(&(p_sync->mutex));
munmap(addr_sync, sizeof(shared_memory_sync));
munmap(addr_data, sizeof(shared_memory_data));
}
int main(int argc, char** argv)
{
if(argc>1)
{
open();
}
else
{
create();
}
return (0);
}
Dieses Programm ausführen, ohne args, dann eine andere Kopie mit args, und der erste wird am assert scheitern die pthread_cond_signal()
überprüfen. Aber die Reihenfolge der zu mmap()
werden open()
Funktion ändern Sie die "/sync
"Speicher vor den "/data"
und alles funktioniert.
Das ist wie ein großer Fehler in LynxOS mir scheint, aber LynuxWorks behauptet, dass mit Mutex und Bedingungsvariablen innerhalb namens Shared Memory auf diese Weise wird durch den POSIX-Standard nicht abgedeckt, so dass sie nicht interessiert.
Kann jemand festzustellen, ob dieser Code nicht verletzt tatsächlich POSIX?
Oder hat jemand eine überzeugende Dokumentation, dass es POSIX-kompatibel ist?
Bearbeiten: wir wissen, dass PTHREAD_PROCESS_SHARED
ist POSIX und wird von LynxOS unterstützt. Der Bereich der Konkurrenz ist, ob Mutexe und Semaphore innerhalb des benannten shared memory verwendet werden können (wie wir es getan haben) oder ob POSIX nur erlaubt, sie zu verwenden, wenn ein Prozess den gemeinsamen Speicher erstellt und mmapt und dann den zweiten Prozess gibt.
Ich frage mich, wie sie sich genau vorstellen, die gleiche Variable mit PTHREAD_PROCESS_SHARED zwischen zwei Prozessen zu teilen (was eindeutig besagt, dass * ein * Mechanismus der Aufteilung der Variablen zwischen Prozessen existieren soll.) Und AFAIK verbietet keine Mutexe und Semaphore wo immer du willst , also "nicht abgedeckt" bedeutet "sollte sich wie gewohnt verhalten". –