2010-01-18 16 views

risposta

28

anziché l'oggetto Java che si usa aspettare/notifica, avete bisogno di due oggetti: un mutex ed una variabile di condizione . Questi sono inizializzati con pthread_mutex_init e pthread_cond_init.

Dove si sarebbe sincronizzato sull'oggetto Java, utilizzare pthread_mutex_lock e pthread_mutex_unlock (notare che in C è necessario accoppiarli manualmente). Se non è necessario attendere/notificare, basta bloccare/sbloccare, quindi non è necessario la variabile di condizione, solo il mutex. Ricorda che i mutex non sono necessariamente "ricorsivi", questo significa che se stai già tenendo il blocco, non puoi riprenderlo a meno che non imposti il ​​flag di init per dire che vuoi quel comportamento.

Dove si sarebbe chiamato java.lang.Object.wait, chiamare pthread_cond_wait o pthread_cond_timedwait.

Dove si chiamerebbe java.lang.Object.notify, chiamare pthread_cond_signal.

Dove si chiamerebbe java.lang.Object.notifyAll, chiamare pthread_cond_broadcast.

Come in Java, le funzioni di attesa sono possibili tramite le funzioni di attesa, quindi è necessario impostare una condizione prima della chiamata, quindi controllare dopo l'attesa della chiamata e chiamare pthread_cond_wait in un ciclo. Come in Java, il mutex viene rilasciato mentre stai aspettando.

A differenza di Java, dove non è possibile chiamare notify a meno che non si tiene il monitor, è possibile in realtà chiamare pthread_cond_signal senza tenere il mutex. Normalmente non ti guadagna nulla, ed è spesso una pessima idea (perché normalmente vuoi bloccare - imposta condizione - segnale - sblocca). Quindi è meglio ignorarlo e trattarlo come Java.

Non c'è molto di più, il modello di base è lo stesso di Java e non per coincidenza. Leggi la documentazione per tutte quelle funzioni, però, perché ci sono vari flag e comportamenti divertenti che vuoi sapere e/o evitare.

In C++ si può fare qualcosa di meglio che usare semplicemente l'API pthreads. Dovresti almeno applicare RAII al blocco/sblocco mutex, ma a seconda di quali librerie C++ puoi usare, potresti usare un ulteriore wrapper C++ per le funzioni pthreads.

4

Utilizzando Condition Variables è un modo per farlo: questi sono disponibili quando si utilizza la libreria pthread sotto Linux (vedi link).

Una variabile condizione è una variabile di tipo pthread_cond_t ed è usato con le funzioni appropriate per l'attesa e successivamente, la continuazione del processo.

1

Se disponibile, è possibile utilizzare i semafori POSIX. La libreria pthread ha mutex, che potrebbero funzionare anche per te. Google si ...

6

pthread_cond_wait e pthread_cond_signal può essere utilizzato per sincronizzare base a una condizione

2

Se non ti interessa la portabilità, Linux offre eventfd, che ti dà esattamente ciò che desideri. Ogni eventfd mantiene un contatore interno. Nella modalità predefinita, la lettura dall'evento si blocca se il contatore è zero, altrimenti restituisce immediatamente. La scrittura verrà aggiunta al contatore interno.

La chiamata di attesa sarebbe quindi solo una uint64_t buf_a; read(event_fd, &buf_a, sizeof(buf_a));, in cui buf deve essere un buffer da 8 byte. Per notificare il thread in attesa, si farebbe uint64_t buf_b = 1; write(event_fd, &buf_b, sizeof(buf_b));.

6

Nel titolo, si mescolano insieme C e C++ in modo casuale in "C/C++". Spero, tu non stia scrivendo un programma che è una miscela dei due.

Se si utilizza C++ 11, si troverà un'alternativa portatile e (perché C++, così) molto più sicura/più facile da usare per pthreads (su sistemi POSIX, di solito utilizza pthreads sotto il cofano) .

È possibile utilizzare std::condition_variable + std::mutex per attendere/notificare. This example mostra come:

#include <iostream> 
#include <string> 
#include <thread> 
#include <mutex> 
#include <condition_variable> 

std::mutex m; 
std::condition_variable cv; 
std::string data; 
bool mainReady = false; 
bool workerReader = false; 

void worker_thread() 
{ 
    // Wait until main() sends data 
    { 
     std::unique_lock<std::mutex> lk(m); 
     cv.wait(lk, []{return mainReady;}); 
    } 

    std::cout << "Worker thread is processing data: " << data << std::endl; 
    data += " after processing"; 

    // Send data back to main() 
    { 
     std::lock_guard<std::mutex> lk(m); 
     workerReady = true; 
     std::cout << "Worker thread signals data processing completed\n"; 
    } 
    cv.notify_one(); 
} 

int main() 
{ 
    std::thread worker(worker_thread); 

    data = "Example data"; 
    // send data to the worker thread 
    { 
     std::lock_guard<std::mutex> lk(m); 
     mainReady = true; 
     std::cout << "main() signals data ready for processing\n"; 
    } 
    cv.notify_one(); 

    // wait for the worker 
    { 
     std::unique_lock<std::mutex> lk(m); 
     cv.wait(lk, []{return workerReady;}); 
    } 
    std::cout << "Back in main(), data = " << data << '\n'; 


    // wait until worker dies finishes execution 
    worker.join(); 
} 

Questo codice mette in evidenza anche alcuni altri punti di forza che C++ ha più di C:

  1. questo codice non contiene un solo puntatore RAW (which are treacherous)
  2. lambda expressions
  3. tutto tipi di altri syntactic swagg.
Problemi correlati