2012-02-13 4 views
6

Utilizzo trylock:Come usare pthread_mutex_trylock?

FILE   *fp; 
pthread_mutex_t demoMutex; 

void * printHello (void* threadId) 
{ 
    pthread_mutex_trylock (&demoMutex); 

    pthread_t  writeToFile = pthread_self(); 
    unsigned short iterate; 
    for (iterate = 0; iterate < 10000; iterate++) 
    { 
     fprintf (fp, " %d ", iterate,   4); 
     fprintf (fp, " %lu ", writeToFile, sizeof (pthread_t)); 
     fprintf (fp, "\n",  writeToFile, 1); 
    } 

    pthread_mutex_unlock (&demoMutex); 
    pthread_exit (NULL); 
} 

e poi main():

int main() 
{ 
    pthread_t  arrayOfThreadId [5]; 
    int     returnValue; 
    unsigned int iterate; 

    fp = fopen ("xyz", "w"); 
    pthread_mutex_init (&demoMutex, NULL); 

    for (iterate = 0; iterate < 5; iterate++) 
    { 
     if (returnValue = pthread_create (&arrayOfThreadId [iterate], 
            NULL, 
            printHello, 
            (void*) &arrayOfThreadId [iterate]) != 0) 
     { 
      printf ("\nerror: pthread_create failed with error number %d", returnValue); 
     } 
    } 

    for (iterate = 0; iterate < 5; iterate++) 
     pthread_join (arrayOfThreadId [iterate], NULL); 

    return 0; 
} 

Qui l'uscita prima stampa alcune del primo filetto e il resto, e poi di nuovo la prima. Il blocco non funziona. Se sostituisco lo stesso con pthread_mutex_lock ogni cosa viene mostrata molto in sequenza!

Qual è l'errore ridicolo qui?

risposta

21

Non ha senso chiamare pthread_mutex_trylock() senza testare il risultato.

Se non riesce ad acquisire il mutex, si dovrebbe non entrare nella sezione critica, e si dovrebbe non sbloccarlo successivamente. Ad esempio, è possibile riscrivere in questo modo (si noti che anche tu sei molto confuso su come dovrebbe essere chiamato fprintf()):

void *printHello(void *threadId) 
{ 
    if (pthread_mutex_trylock(&demoMutex) == 0) 
    { 
     unsigned short iterate; 
     for (iterate = 0; iterate < 10000; iterate++) 
     { 
      fprintf (fp, " %d\n", iterate); 
     } 

     pthread_mutex_unlock (&demoMutex); 
    } 

    pthread_exit (NULL); 
} 

Tuttavia, probabilmente più sensato utilizzare pthread_mutex_lock() invece di pthread_mutex_trylock(), in modo che il filo aspetterà che il mutex sia disponibile se è conteso. pthread_mutex_lock() è in quasi tutti i casi quello che vuoi; la variante _trylock è solo per l'ottimizzazione di alcuni casi insoliti - se si verifica una situazione in cui è necessario _trylock, lo saprai.

+0

Per curiosità, puoi fornire un esempio in cui '..._ lock()' è preferito a '..._ trylock()'? Ex. se si vuole implementare un timeout, non sarebbe 'trylock' la scelta? O non ha senso fare un timeout? – theMayer

+1

'..._ lock()' è l'opzione appropriata nella maggior parte dei casi, perché nella maggior parte dei casi, il thread non può fare progressi utili in avanti senza prendere il mutex. In questo caso, se viene usato un '... trylock()' e non può prendere il lucchetto, l'unica opzione è di aggirare e tentare di bloccarlo di nuovo. I timeout devono essere richiesti solo nei casi in cui è richiesto un evento esterno per il progresso in avanti, che tende a mappare una variabile di condizione e quindi è possibile utilizzare 'pthread_cond_timedwait()'. Un'attesa illimitata su un mutex indica un problema nel codice stesso piuttosto che una condizione eccezionale. – caf

+0

Sono d'accordo con l'ultima frase ... Ho qualche codice legacy in cui lo sviluppatore è diventato un po 'troppo ambizioso e forse non ha capito come funziona il threading. Il codice sta anche tentando di sospendere il thread per un singolo millisecondo alla volta. Devi ridere, altrimenti ti fa piangere! – theMayer

0

Il codice si intende bloccare per garantire l'esclusione reciproca dove si chiama pthread_mutex_trylock(). Altrimenti è un comportamento indefinito. Pertanto è necessario chiamare il numero pthread_mutex_lock().

0

una versione modificata della forza bloccata con ciclo while dovrebbe essere più stabile.

void *printHello(void *threadId) 

{ 

    while (pthread_mutex_trylock(&demoMutex) == 0) 

    { 

     unsigned short iterate; 

     for (iterate = 0; iterate < 10000; iterate++) 

     { 

      fprintf (fp, " %d\n", iterate); 

     } 


     pthread_mutex_unlock (&demoMutex); 

     break; 

    } 

pthread_exit (NULL); 

} `

4
... 
while (pthread_mutex_trylock(&demoMutex) == 0) 
... 

Il codice non ha senso. Dov'è la forza bloccata? È come uno spinlock non funzionante che usa più CPU ?!

trylock restituisce 0 quando non si blocca, quindi:

if(!pthread_mutex_trylock(&demoMutex)) 
{ 
    // mutex locked 
} 

La funzione pthread_mutex_trylock() deve restituire zero se un blocco sul l'oggetto mutex fa riferimento mutex è acquisito. In caso contrario, viene restituito un numero di errore per indicare l'errore.

0

L'uso di pthread_mutex_trylock viene utilizzato per garantire che tou non causi una corsa a un comando specifico. Per fare ciò, è necessario utilizzare pthread_mutex_trylock come condizione! un non dare per scontato che funzionerebbe da solo. example- while (pthread_mutex_trylock (& my_mutex) == 0) { printf ("Il mutex è nel mio controllo !!\ N ");. }

in questo modo si può essere sicuri che, anche se il mutex è bloccato, si sta facendo abusy-attesa che in quel particolare filo

3

CAF ha avuto una grande risposta su come Ho solo dovuto afferrare questa spiegazione per me stesso, tuttavia ho appreso che lo pthread_mutex_lock() ha superato di gran lunga il sovraccarico in classe e l'ho appena testato usando il <time.h> lib e le prestazioni per il mio loop sono aumentate in modo significativo. centesimi poiché ha detto che forse dovresti usare pthread_mutex_lock() invece!

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

#define NUM_THREADS 4 
#define LOOPS 100000 

int counter; 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

// using pthread_mutex_lock 
void* worker() { 
    for (int i = 0; i < LOOPS; i++) { 
     pthread_mutex_lock(&mutex); 
     counter++; 
     pthread_mutex_unlock(&mutex); 
    } 
    pthread_exit(NULL); 
} 

// using try_lock - obviously only use one at a time 
void* worker() { 
    for (int i = 0; i < LOOPS; i++) { 
     while (pthread_mutex_trylock(&mutex) != 0) { 
      // wait - treated as spin lock in this example 
     } 

     counter++; 
     pthread_mutex_unlock(&mutex); 
    } 
    pthread_exit(NULL); 
} 

int main(int argc, char *argv[]) { 
    clock_t begin = clock(); 
    pthread_t t[NUM_THREADS]; 
    int rc; 

    counter = 0; 

    for (int i = 0; i < NUM_THREADS; i++) { 
     rc = pthread_create(&t[i], NULL, worker, NULL); 

     if (rc) { 
      printf("Thread #%d failed\n", i); 
     } 
    } 

    for (int i = 0; i < NUM_THREADS; i++) { 
     pthread_join(t[i], NULL); 
    } 

    printf("%d\n", counter); 
    clock_t end = clock(); 
    double time = (double)(end - begin)/CLOCKS_PER_SEC; 

    printf("Time Spent: %f", time); 

    return 0; 
} 

Ovviamente si commenterebbe un lavoratore per testarlo, ma se lo provi, ottengo Time Spent: 1.36200 come media per pthread_mutex_lock() e Time Spent: 0.36714 per pthread_mutex_trylock().

Torna di nuovo se usi Atomics.

+0

Questa risposta merita un voto alto. Per alcune situazioni, devi usare _trylock, ma assicurati di controllare il risultato del risultato. –

+0

Mi chiedo se lo spin lock in questo caso potrebbe essere la causa dell'aumento delle prestazioni? Vedi https://stackoverflow.com/questions/6603404/when-is-pthread-spin-lock-the-right-thing-to-use-over-e-g-a-pthread-mutex – theMayer