Domanda

C'è qualche svantaggio nel chiamare pthread_cond_timedwait senza prima prendere un lucchetto sul mutex associato e anche non prendere un lucchetto mutex quando si chiama pthread_cond_signal?

Nel mio caso non c'è davvero alcuna condizione da verificare, voglio un comportamento molto simile a Java wait (long) e notification ().

Secondo la documentazione, ci possono essere "comportamenti di pianificazione imprevedibili". Non sono sicuro di cosa significhi.

Un programma di esempio sembra funzionare bene senza prima bloccare i mutex.

È stato utile?

Soluzione

Il primo non è OK:

  

Il pthread_cond_timedwait () e   Le funzioni pthread_cond_wait () devono   blocco su una variabile di condizione. Essi   deve essere chiamato con mutex bloccato da   il thread chiamante o non definito   risultati del comportamento.

http://opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html

Il motivo è che l'implementazione potrebbe voler fare affidamento sul blocco del mutex per aggiungere in modo sicuro un elenco di camerieri. E potrebbe voler rilasciare il mutex senza prima averlo verificato.

Il secondo è inquietante:

  

se è prevedibile un comportamento di pianificazione   richiesto, quindi quel mutex è bloccato da   il thread chiama    pthread_cond_signal () o    pthread_cond_broadcast () .

http://www.opengroup.org/onlinepubs/007908775/xsh/ pthread_cond_signal.html

In cima alla mia testa, non sono sicuro di quale sia la specifica condizione di gara che incasina il comportamento dello scheduler se segnali senza prendere il lucchetto. Quindi non so quanto male possa comportare il comportamento dello scheduler indefinito: ad esempio, forse con la trasmissione i camerieri non ottengono il blocco in ordine di priorità (o comunque il tuo particolare programmatore si comporta normalmente). O forse i camerieri possono perdere " perso " ;.

Generalmente, tuttavia, con una variabile di condizione si desidera impostare la condizione (almeno una bandiera) e il segnale, piuttosto che solo il segnale, e per questo è necessario prendere il mutex. Il motivo è che altrimenti, se si è in concomitanza con un altro thread che chiama wait (), si ottiene un comportamento completamente diverso a seconda che wait () o signal () vince: se il segnale () si insinua per primo, quindi si attendere il timeout completo anche se il segnale che ti interessa è già accaduto. Questo è raramente ciò che vogliono gli utenti delle variabili di condizione, ma potrebbe andare bene per te. Forse questo è ciò che i documenti intendono per "comportamento imprevedibile dello scheduler" - improvvisamente il timeslice diventa critico per il comportamento del tuo programma.

A proposito, in Java devi avere il blocco per poter avvisare () o notifyAll ():

  

Questo metodo dovrebbe essere chiamato solo da a   thread che è il proprietario di questo   monitor dell'oggetto.

http: // java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#notify ()

Il comportamento sincronizzato di Java {/} / wait / notifty / notifyAll è analogo a pthread_mutex_lock / pthread_mutex_unlock / pthread_cond_wait / pthread_cond_signal / pthread_cond_broadcast e non per coincidenza.

Altri suggerimenti

Butenhof è eccellente "Programmazione con thread POSIX" discute questo diritto alla fine del capitolo 3.3.3.

Fondamentalmente, segnalare la condvar senza bloccare il mutex è un potenziale ottimizzazione delle prestazioni: se il thread di segnalazione ha il mutex bloccato, il thread che si sveglia sulla condvar deve bloccare immediatamente sul mutex che il il thread di segnalazione si è bloccato anche se il thread di segnalazione non sta modificando nessuno dei dati che verrà utilizzato dal thread in attesa.

Il motivo per cui "comportamento imprevedibile dello scheduler" è menzionato che se hai un thread ad alta priorità in attesa sulla condvar (che un altro thread sta per segnalare e riattivare il thread ad alta priorità), qualsiasi altro thread con priorità inferiore può venire e bloccare il mutex in modo che quando la condvar è segnalato e il thread ad alta priorità viene risvegliato, deve attendere il thread con priorità inferiore per rilasciare il mutex. Se il mutex è bloccato durante la segnalazione, il thread con priorità più alta verrà programmato sul mutex prima del thread con priorità inferiore: in pratica lo sai che quando ti "svegli". il thread ad alta priorità che si risveglierà non appena lo scheduler lo consente (ovviamente, potresti dover attendere il mutex prima di segnalare il thread ad alta priorità, ma questo è un problema diverso).

Il punto di attesa sulla variabile condizionale accoppiata con un mutex è atomicamente immettere wait e rilasciare il blocco, ovvero consentire ad altri thread di modificare lo stato protetto, quindi ricevere atomicamente di nuovo la notifica del cambio di stato e acquisire la serratura. Quello che descrivi può essere fatto con molti altri metodi come pipe, prese, segnali o - probabilmente il più appropriato - semafori .

Penso che dovrebbe funzionare (nota il codice non testato):

// initialize a semaphore
sem_t sem;
sem_init(&sem,
    0, // not shared
    0  // initial value of 0
    );


// thread A
struct timespec tm;
struct timeb    tp;

const long sec      = msecs / 1000;
const long millisec = msecs % 1000;

ftime(&tp);
tp.time += sec;
tp.millitm += millisec;
if(tp.millitm > 999) {
    tp.millitm -= 1000;
    tp.time++;
}
tm.tv_sec  = tp.time;
tm.tv_nsec = tp.millitm * 1000000;

// wait until timeout or woken up
errno = 0;
while((sem_timedwait(&sem, &tm)) == -1 && errno == EINTR) {
    continue;
}

return errno == ETIMEDOUT; // returns true if a timeout occured


// thread B
sem_post(&sem); // wake up Thread A early

Le condizioni dovrebbero essere segnalate al di fuori del mutex quando possibile. I mutex sono un male necessario nella programmazione concorrente. Il loro uso porta alla contesa che ruba al sistema le massime prestazioni che può ottenere dall'uso di più processori.

Lo scopo di un mutex è quello di proteggere l'accesso ad alcune variabili condivise nel programma in modo che si comportino atomicamente. Quando un'operazione di segnalazione viene eseguita all'interno di un mutex, provoca l'inclusione di centinaia di cicli macchina irrilevanti nel mutex che non hanno nulla a che fare con la protezione dei dati condivisi. Potenzialmente, chiama da uno spazio utente fino in fondo in un kernel.

Le note sul "comportamento programmatore prevedibile" nello standard sono completamente fasulli.

Quando vogliamo che la macchina esegua le istruzioni in un ordine prevedibile e ben definito, lo strumento è la sequenza di istruzioni all'interno di un singolo thread di esecuzione: S1; S2 . L'istruzione S1 è " pianificato " prima di S2 .

Usiamo i thread quando ci rendiamo conto che alcune azioni sono indipendenti e il loro ordine di pianificazione non è importante, e ci sono vantaggi in termini di prestazioni da realizzare, come una risposta più tempestiva a eventi in tempo reale o l'elaborazione su più processori.

A volte quando gli ordini di pianificazione diventano importanti tra più thread, questo rientra in un concetto chiamato priorità . La priorità risolve ciò che accade prima quando una qualsiasi delle istruzioni N potrebbe essere programmata per l'esecuzione. Un altro strumento per ordinare in multithreading è l'accodamento. Gli eventi vengono inseriti in una coda da uno o più thread e un singolo thread di servizio elabora gli eventi nell'ordine della coda.

La linea di fondo è che il posizionamento di pthread_cond_broadcast non è uno strumento appropriato per controllare l'ordine di esecuzione. Non renderà prevedibile l'ordine di esecuzione, nel senso che improvvisamente il programma ha esattamente lo stesso comportamento riproducibile su ogni piattaforma.

"comportamento di pianificazione imprevedibile" significa proprio questo. Non sai cosa succederà. Né l'implementazione. Potrebbe funzionare come previsto. Potrebbe arrestare in modo anomalo la tua app. Potrebbe funzionare benissimo per anni, quindi una condizione di gara fa diventare la tua app scimmia. Potrebbe bloccarsi.

Fondamentalmente se qualche documento suggerisce che qualcosa di indefinito / imprevedibile può accadere a meno che tu non faccia ciò che ti dicono di fare, è meglio che tu lo faccia. Altrimenti potrebbero esplodere in faccia. (E non esploderà finché non metterai in produzione il codice, solo per infastidirti ancora di più. Atleast è la mia esperienza)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top