18

Questa è una domanda di intervista.È possibile utilizzare il mutex in caso di multiprocessing su Linux/UNIX?

È possibile utilizzare il mutex in caso di multiprocessing su Linux/UNIX?

La mia idea: No, diversi processi hanno spazio di memoria separato.

mutex viene utilizzato solo per il multithreading.

il semaforo viene utilizzato per la multielaborazione per eseguire la sincronizzazione.

giusto?

Qualsiasi commento è benvenuto.

grazie

+0

Dipende da cosa si intende per "multiprocessing". Se si utilizza la definizione stackoverflow, il multiprocessing includerà il multithreading. Se intendi "più processi", hai ragione. –

+0

Vedere http://stackoverflow.com/a/28479697/2189128 – Jeff

risposta

18
Mutual exclusion locks (mutexes) prevent multiple threads 
from simultaneously executing critical sections of code that 
access shared data (that is, mutexes are used to serialize 
the execution of threads). All mutexes must be global. A 
successful call for a mutex lock by way of mutex_lock() 
will cause another thread that is also trying to lock the 
same mutex to block until the owner thread unlocks it by way 
of mutex_unlock(). Threads within the same process or 
within other processes can share mutexes. 

Mutexes can synchronize threads within the **same process** or 
in ***other processes***. Mutexes can be used to synchronize 
threads between processes if the mutexes are allocated in 
writable memory and shared among the cooperating processes 
(see mmap(2)), and have been initialized for this task. 

Initialize mutex sono o intra-processo o tra processi, a seconda sul argomento passato implicitamente o esplicitamente al di inizializzazione di quel mutex. Un mutex assegnato in modo statico non deve essere inizializzato esplicitamente; per impostazione predefinita, un mutex assegnato in modo statico viene inizializzato con tutti gli zeri e il suo ambito è impostato per rientrare nel processo di chiamata.

For inter-process synchronization, a mutex needs to be allo- 
cated in memory shared between these processes. Since the 
memory for such a mutex must be allocated dynamically, the 
mutex needs to be explicitly initialized using mutex_init(). 
+10

inoltre, per la sincronizzazione tra processi, oltre al requisito da allocare nella memoria condivisa, i mutex devono utilizzare anche l'attributo PTHREAD_PROCESS_SHARED, altrimenti l'accesso al mutex da un altro processo rispetto al suo creatore risulta in un comportamento indefinito (si veda: http: // linux.die.net/man/3/pthread_mutexattr_setpshared): "L'attributo condiviso dal processo è impostato su PTHREAD_PROCESS_SHARED per consentire a un mutex di essere utilizzato da qualsiasi thread che abbia accesso alla memoria a cui è assegnato il mutex, anche se il mutex è allocato in memoria che è condiviso da più processi " – user1284631

5

Non proprio. I thread POSIX hanno un concetto di process-shared attribute che può essere utilizzato per creare mutex che possono essere gestiti da più processi.

È possibile inserire un tale mutex nella memoria condivisa in modo che possano essere raggiunti da più processi.

Se LINUX implementa questo, non sono sicuro, non ho mai avuto bisogno di usarlo poiché sembra inutilmente complesso.

Per un utile riassunto degli attributi, vedere la risposta a this question.

0

Sì, in generale in Linux abbiamo solo mutex senza nome a causa dei quali non possono operare tra i processi. Abbiamo bisogno di un semaforo per superarlo.

In Windows, hanno un concetto di mutex denominato che ci consente di utilizzare i mutex tra i processi.

+4

Vedere http://linux.die.net/man/3/pthread_mutexattr_init - LINUX consente i mutex condivisi dal processo. Sia che siano nominati o meno non è rilevante qui, Linux e UNIX possono condividerli senza nomi collegandoli ai comuni blocchi di memoria condivisa. – paxdiablo

+0

Sì, è corretto. Puoi usarli collegandoti a blocchi condivisi. :) –

+4

Risposta non accurata. –

7

È abbastanza possibile utilizzare uno process-shared mutex.

In effetti, le applicazioni moderne preferiscono utilizzare un mutex condiviso di processo insieme a una variabile di condizione di processo condivisa su un semaforo perché quest'ultimo è meno flessibile.

Ricordo di aver usato Red Hat Linux nel 2004 e in quel momento supportava sia i mutex condivisi che le variabili condizionali.

2

ero alla ricerca di un mutex denominato in modo che potessi garantire la mutua esclusione per la durata di un processo (assicurandosi che solo un processo in esecuzione per alcune serie di proprietà). Non ne ho trovato uno (sembra che non sia sembrato abbastanza difficile) e quindi ho implementato il mio mutex pseudo chiamato in linux usando un socket di dominio UNIX astratto. Solo un singolo bind() su quel socket avrà successo. L'altra cosa buona è che il SO pulirà il socket del dominio UNIX astratto se il processo muore e quindi non pulisce il socket stesso.Sfortunatamente non sono sicuro che tu possa "aspettare" che questo pseudo mutex diventi disponibile.

Un socket di dominio UNIX astratto è un socket di dominio UNIX il cui nome inizia con un byte null. Attenzione però, credo che l'intero buffer sia usato come nome e quindi vuoi assicurarti di non solo memcpy o strcpy una stringa parziale, o se assicurati di riempire prima l'intero buffer con qualche carattere .

Tutti tranne il primo binding() falliranno con un errno di EADDRINUSE.

// Create an abstract socket to use as a mutex.        

int err; 
int mutex_sock = socket(AF_UNIX, SOCK_STREAM, 0); 
if (mutex_sock == -1) 
    { 
    err = errno; 
    printf("main, failed creating mutex socket: %s\n", 
      get_error_string(errno, error_string, sizeof(error_string))); 
    log_event(LOG_LEVEL_ERROR, "main, failed creating mutex socket: " 
      "%s", get_error_string(errno, error_string, 
      sizeof(error_string))); 
    errno = err; 
    goto done; 
    } 

// Bind to abstract socket. We use this as a sort of named mutex.   

struct sockaddr_un addr; 
memset(&addr, 0, sizeof(addr)); 
addr.sun_family = AF_UNIX; 
strncpy(addr.sun_path + 1, socket_name, sizeof(addr.sun_path) - 2); 
result = bind(mutex_sock, (struct sockaddr*) &addr, sizeof(addr)); 
if (result == -1) 
    { 
    err = errno; 
    if (errno == EADDRINUSE) 
     { 
     printf("main, failed bind to mutex socket: %s. " 
       "Another instance must be running.\n", 
       get_error_string(errno, 
       error_string, sizeof(error_string))); 
     log_event(LOG_LEVEL_ERROR, "main, failed bind to mutex socket: " 
       "%s. " 
       "Another instance must be running.", 
       get_error_string(errno, 
       error_string, sizeof(error_string))); 
     } 
    else 
     { 
     printf("main, failed bind to mutex socket: %s\n", 
       get_error_string(errno, error_string, 
       sizeof(error_string))); 
     log_event(LOG_LEVEL_ERROR, "main, failed bind to mutex socket: %s", 
       get_error_string(errno, error_string, 
       sizeof(error_string))); 
     } 
    errno = err; 
    goto done; 
    } 

Grazie, Nick