2012-02-27 4 views
9

Ho avuto l'impressione che il codice flock(2) sia thread-safe, di recente ho trovato il caso nel codice, dove più thread sono in grado di ottenere un blocco sullo stesso file che sono tutto sincronizzato con l'uso di ottenere un blocco esclusivo usando il c api flock. Il processo 25554 è un'app multi-thread che ha 20 thread, il numero di thread con lock sullo stesso file varia quando si verifica il deadlock. L'app multi-thread testEvent è writer per il file, dove era il push è il lettore dal file. Sfortunatamente il lsof non stampa il valore LWP quindi non riesco a trovare quali sono i thread che stanno tenendo il blocco. Quando si verifica la condizione sotto menzionata, sia il processo che i thread sono bloccati nella chiamata del branco come visualizzato dalla chiamata pstack o strace sul pid 25569 e 25554. Qualche suggerimento su come superare questo in RHEL 4.x.thread multipli in grado di ottenere il gruppo allo stesso tempo

Una cosa che volevo aggiornare è che il flock non si comporta in modo anomalo tutto il tempo, quando la velocità tx dei messaggi è superiore a 2 Mbps solo allora mi trovo in questo problema di deadlock con flock, al di sotto di tale velocità tutto è file. Ho mantenuto la costante num_threads = 20, size_of_msg = 1000bytes e ho appena variato il numero di messaggi tx al secondo a partire da 10 messaggi a 100 messaggi che è 20 * 1000 * 100 = 2 mbps, quando aumento il numero di messaggi a 150 quindi il problema del gregge si verifica

Volevo solo chiedere qual è la tua opinione su flockfile c api.

sudo lsof filename.txt 
    COMMAND  PID  USER  FD  TYPE  DEVICE  SIZE NODE  NAME 
    push   25569 root  11u  REG  253.4  1079 49266853 filename.txt 
    testEvent 25554 root  27uW  REG  253.4  1079 49266853 filename.txt 
    testEvent 25554 root  28uW  REG  253.4  1079 49266853 filename.txt 
    testEvent 25554 root  29uW  REG  253.4  1079 49266853 filename.txt 
    testEvent 25554 root  30uW  REG  253.4  1079 49266853 filename.txt 

Il programma di test multithread che chiamerà la funzione lib write_data_lib_func.

void* sendMessage(void *arg) { 

int* numOfMessagesPerSecond = (int*) arg; 
std::cout <<" Executing p thread id " << pthread_self() << std::endl; 
while(!terminateTest) { 
    Record *er1 = Record::create(); 
    er1.setDate("some data"); 

    for(int i = 0 ; i <=*numOfMessagesPerSecond ; i++){ 
    ec = _write_data_lib_func(*er1); 
    if(ec != SUCCESS) { 
     std::cout << "write was not successful" << std::endl; 

    } 

    } 
    delete er1; 
    sleep(1); 
} 

return NULL; 

Il metodo precedente verrà chiamato in pthreads nella funzione principale del test.

for (i=0; i<_numThreads ; ++i) { 
    rc = pthread_create(&threads[i], NULL, sendMessage, (void *)&_num_msgs); 
    assert(0 == rc); 

}

Qui è la fonte scrittore/lettore, per motivi di proprietà, non volevo solo tagliare e incollare, la fonte scrittore accede più thread in un processo

int write_data_lib_func(Record * rec) {  
if(fd == -1) { 
    fd = open(fn,O_RDWR| O_CREAT | O_APPEND, 0666); 
} 
if (fd >= 0) { 
    /* some code */ 

    if(flock(fd, LOCK_EX) < 0) { 
    print "some error message"; 
    } 
    else { 
    if(maxfilesize) { 
     off_t len = lseek (fd,0,SEEK_END); 
     ... 
     ... 
     ftruncate(fd,0); 
     ... 
     lseek(fd,0,SEEK_SET); 
    } /* end of max spool size */ 
    if(writev(fd,rec) < 0) { 
    print "some error message" ; 
    } 

    if(flock(fd,LOCK_UN) < 0) { 
    print some error message; 
    } 

Nel lato lettore di cose c'è un processo daemon senza thread.

int readData() { 
    while(true) { 
     if(fd == -1) { 
     fd= open (filename,O_RDWR); 
     } 
     if(flock (fd, LOCK_EX) < 0) { 
     print "some error message"; 
     break; 
     } 
     if(n = read(fd,readBuf,readBufSize)) < 0) { 
     print "some error message" ; 
     break; 
     } 
     if(off < n) { 
     if (off <= 0 && n > 0) { 
      corrupt_file = true; 
     } 
     if (lseek(fd, off-n, SEEK_CUR) < 0) { 
      print "some error message"; 
     } 
     if(corrupt_spool) { 
      if (ftruncate(fd,0) < 0) { 
      print "some error message"; 
      break; 
      } 
     } 
     } 
     if(flock(fd, LOCK_UN) < 0) 
     print some error message ; 
     } 
    }  
} 
+0

Puoi pubblicare il codice che chiama 'flock'? Un programma di test [semplice] (http://sscce.org) sarebbe bello. – phihag

+0

AFAIK, i blocchi di avviso non garantiscono la coerenza. http://www.gsp.com/cgi-bin/man.cgi?section=2&topic=flock – zengr

risposta

8

flock(2) è documentato come "blocco se un blocco incompatibile viene mantenuto da un altro processo " e con "blocchi creati da flock() sono associati ad un elemento della tabella file aperto", quindi dovrebbe essere previsto che i blocchi di flock bloccati da più thread dello stesso processo non interagiscano. (documentazione flock non parlare di thread).

Quindi, la soluzione deve essere semplice per voi: associare un pthread_mutex_t ad ogni flock descrittore di file -able, e proteggere la chiamata a flock con quel mutex. È inoltre possibile utilizzare pthread_rwlock_t se si desidera un blocco di lettura e scrittura.

+0

?? Dov'è il codice sorgente ??? –

+0

Ora ho aggiunto la fonte. – user1235176

+0

grazie per la tua risposta Sono sicuro che stavo pensando nella stessa linea per associare un mutex con flock, quello che mi dava fastidio era il flock (2) che si trova sopra fcntl (2), e fcntl (2) lockf (2) ha affermato di thread sicuro, quindi è stata una sorpresa per me che questo non è. – user1235176

2

Dalla pagina Linux man per flock (2):

Locks create da flock() sono associati con una voce di tabella file aperto. Ciò significa che i descrittori di file duplicati (creati, ad esempio, da fork (2) o dup (2)) si riferiscono allo stesso blocco e questo blocco può essere modificato o rilasciato utilizzando uno qualsiasi di questi descrittori. Inoltre, il blocco viene rilasciato mediante un'operazione LOCK_UN esplicita su uno qualsiasi di questi descrittori duplicati o quando tutti questi descrittori sono stati chiusi.

Inoltre, affollano le serrature non 'pila', quindi se si tenta di acquisire un blocco già in possesso, la chiamata gregge è un noop che restituisce immediatamente senza bloccare e senza modificare lo stato di blocco in alcun modo .

Poiché i thread all'interno di un processo condividono descrittori di file, è possibile raggruppare il file più volte da thread diversi e non si bloccherà, poiché il blocco è già in attesa.

anche dalle note sul flock (2):

flock() e fcntl (2) serrature hanno semantica diversa rispetto processi biforcuta e dup (2). Sui sistemi che implementano flock() usando fcntl (2), la semantica di flock() sarà diversa da quelle descritte in questa pagina di manuale.

+0

Questo non è vero chris se vedi il mio output di lsof i descrittori di file sono unici per ogni thread. – user1235176

+2

I thread all'interno di un processo descrivono i descrittori di file. Vedere http://stackoverflow.com/questions/6223776/threads-and-file-descriptors EDIT ---- E penso che molti di noi che hanno scritto programmi multi-thread abbiano scritto codice funzionante in cui file i descrittori sono condivisi tra thread. –

+0

Questa dovrebbe essere la risposta accettata ... –

Problemi correlati