2010-12-31 4 views
6

Mam problem z Valgrind mówi mi, że mam jakąś pamięć możliwą przegrane:pthread_create następnie pthread_detach nadal skutkuje ewentualnie utracone błędu w Valgrind

==23205== 544 bytes in 2 blocks are possibly lost in loss record 156 of 265 
==23205== at 0x6022879: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==23205== by 0x540E209: allocate_dtv (in /lib/ld-2.12.1.so) 
==23205== by 0x540E91D: _dl_allocate_tls (in /lib/ld-2.12.1.so) 
==23205== by 0x623068D: [email protected]@GLIBC_2.2.5 (in /lib/libpthread-2.12.1.so) 
==23205== by 0x758D66: MTPCreateThreadPool (MTP.c:290) 
==23205== by 0x405787: main (MServer.c:317) 

kod, który tworzy te wątki (MTPCreateThreadPool) w zasadzie dostaje indeks do bloku oczekujących gniazd pthread_t i tworzy z tym wątek. TI staje się wskaźnikiem do struktury, która ma indeks wątku i pthread_t. (Uproszczony/odkażane):

for (tindex = 0; tindex < NumThreads; tindex++) 
    { 
    int rc; 
    TI = &TP->ThreadInfo[tindex]; 
    TI->ThreadID = tindex; 

    rc = pthread_create(&TI->ThreadHandle,NULL,MTPHandleRequestsLoop,TI); 
    /* check for non-success that I've omitted */ 
    pthread_detach(&TI->ThreadHandle); 
    } 

Następnie mamy MTPDestroyThreadPool funkcyjny że pętle przez wszystkich wątków, które stworzyliśmy i anuluje ich (ponieważ MTPHandleRequestsLoop nie exit).

for (tindex = 0; tindex < NumThreads; tindex++) 
    { 
    pthread_cancel(TP->ThreadInfo[tindex].ThreadHandle); 
    } 

czytałem gdzie indziej (w tym inne pytania tutaj na SO), że odłączenie wątku wyraźnie uniemożliwiłoby to ewentualnie utracone błąd, ale to oczywiście nie jest. jakieś pomysły?

Odpowiedz

4

Jednym z powodów może być to, że pthread_cancel w rzeczywistości nie anuluje wątku - nie jest to gwarantowane. Anulowanie wątku jest asynchroniczne; pthread_cancel zwraca natychmiast, ale anulowanie może zostać odroczone do następnego punktu anulowania. W takim przypadku wątki mogą nadal znajdować się w pobliżu, gdy Valgrind gromadzi statystyki.

+0

To było również to, co miałem zasugerować, i ewentualnie przetestować wartość zwracaną 'pthread_cancel' –

+0

Więc jeśli któryś z wątków (potencjalnie wszystkie) blokuje semafor, anulowanie natychmiast powróci, ale ponieważ ' ponownie zablokowane jest całkowicie prawdopodobne, że proces głównego serwera zakończy się, zanim faktycznie anuluje? – alesplin

+0

sem_wait jest punktem anulowania (http://compute.cnr.berkeley.edu/cgi-bin/man-cgi?cancellation+5), więc jeśli wątek będzie można anulować, oczekiwanie powinno zostać anulowane natychmiast. Wirowanie nici w nieskończonej pętli jest lepszym kandydatem. Należy jednak najpierw ustalić, czy tak się dzieje, tj. Czy wątki zostaną anulowane, czy nie. –

8

Implementacja wątków glibc celowo przecieka pamięć. Zachowuje pamięć przydzieloną do kontekstu wątku w pamięci podręcznej, aby ponownie użyć przy następnym utworzeniu wątku. Zrobiłem benchmarking w porównaniu do implementacji bez buforowania i wygląda na to, że buforowanie goli o 50% mniej optymalnego czasu dla pthread_create, ale drastycznie spowalnia pthread_join, z powodu straty netto. Oczywiście nadal jest to (mały) zysk, jeśli zależy Ci na opóźnieniu tworzenia wątku, a nie na przepustowości.

Należy również zauważyć, że bardzo trudno jest zwolnić wątek, aby zwolnić jego kontekst, nawet jeśli chciał. W przypadku wątku, który można połączyć, wątek, który wywołuje pthread_join, może zwolnić kontekst, ale odłączony wątek musi być w stanie działać bez stosu podczas przerwy między zwolnieniem jego kontekstu i zakończeniem się. Można to osiągnąć tylko pisząc ten mały fragment kodu w czystym asm.

Zastanawiasz się, w jaki sposób konteksty wolnostojących wątków są zwracane do pamięci podręcznej bez podobnych warunków wyścigu? Linux ma funkcję zerowania numeru int pod określonym adresem (zarejestrowanym przez bibliotekę wątków przestrzeni użytkownika) po zakończeniu wątku. W związku z tym wątek może bezpiecznie dodać własny kontekst do pamięci podręcznej, ponieważ dopóki nie zostanie przerwany, inne wątki nadal będą wyświetlały niezerową wartość (zwykle identyfikator wątku) pod tym adresem i będą interpretować, że kontekst jest nadal w użyciu.

0

Tworzenie nici, które można łączyć w celu natychmiastowego odłączenia, nie ma dla mnie większego sensu. Stwarza to tylko dodatkowe koszty dla systemu.

Zacznę wątki oderwane od początku, masz swoją wspólną strukturę danych ThreadInfo, aby kontrolować swoje wątki.

Również powinienem mieć flagę lub coś podobnego w swoim argumencie na wątek ThreadInfo, który nakazuje wątkowi wyłączenie w kontrolowany sposób.

+0

Dobra uwaga. Nie napisałem tego kodu, szukam tylko przyczyny (i wyleczenia) "możliwej do zgubienia" wiadomości w Valgrind, ale mogę to naprawić, gdy jestem na tym. – alesplin