Lo standard POSIX consente a un denominato di memoria condivisa di contenere un mutex e una variabile di condizione?Condizione variabile nella memoria condivisa - questo codice è conforme al codice POSIX?
Abbiamo cercato di utilizzare una variabile mutex e condizione per sincronizzare l'accesso alla memoria condivisa denominata da due processi su un LynuxWorks LynxOS-SE system (conforme a POSIX).
Un blocco di memoria condivisa è chiamato "/sync"
e contiene il mutex e la variabile di condizione, l'altro è "/data"
e contiene i dati effettivi a cui si sta sincronizzando l'accesso.
Stiamo vedendo gli errori da pthread_cond_signal()
se entrambi i processi non svolgono le mmap()
chiamate in esattamente nello stesso ordine, oppure, se uno mmaps processo in qualche altro pezzo di memoria condivisa prima che la memoria mmaps "/sync"
.
Questo codice di esempio è di circa il più breve posso farlo:
#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);
}
Esegui il programma senza argomenti, poi un'altra copia con args, e il primo che non riuscirà a l'asserzione verifica della pthread_cond_signal()
. Ma cambiare l'ordine della funzione open()
al mmap()
"memoria "/sync
prima del "/data"
e sarà tutto bene il lavoro.
Questo mi sembra un bug importante in LynxOS a me, ma LynuxWorks sostengono che usando mutex e variabili condizioni all'interno memoria condivisa chiamato in questo modo non è coperto dallo standard POSIX, quindi non sono interessati.
qualcuno può determinare se questo codice fa in realtà viola POSIX?
O qualcuno ha qualche documentazione convincente che è conforme a POSIX?
Modifica: sappiamo che PTHREAD_PROCESS_SHARED
è POSIX ed è supportato da LynxOS. L'area di conflitto è se i mutex e i semafori possono essere utilizzati all'interno della memoria condivisa denominata (come abbiamo fatto) o se POSIX li consente di essere utilizzati solo quando un processo crea e mmap la memoria condivisa e quindi avvia il secondo processo.
Mi chiedo come immaginino esattamente di condividere la stessa variabile usando PTHREAD_PROCESS_SHARED tra due processi (il che implica chiaramente * alcuni * meccanismi di condivisione della variabile tra i processi dovrebbe esistere.) E AFAIK nessuno standard proibisce il posizionamento di mutex e semafori ovunque tu voglia , quindi "non coperto" significa "dovrebbe comportarsi come al solito". –