2012-04-12 14 views
38

Nowe C++ ma ten typ std :: thread. Działa jak marzenie. Teraz chciałbym nadać każdemu wątkowi nazwę dla łatwiejszego debugowania (jak na przykład java). Z pthreads zrobiłbym:std :: thread - nazewnictwo twojego wątku

pthread_setname_np(pthread_self(), "thread_name"); 

ale w jaki sposób mogę to zrobić z C++ 0x? Wiem, że używa on pthreads pod systemem Linux, ale chciałbym, aby moja aplikacja była przenośna. Czy to w ogóle możliwe?

+1

W systemie Windows nazwa wątku jest właściwością debuggera (tj. Jest śledzona poza samą aplikacją). W rezultacie nie masz odpowiednika 'pthread_getname_np' – MSalters

Odpowiedz

26

Przenośnym sposobem, aby to zrobić, jest zachowanie mapy nazw, wpisanej przez identyfikator wątku, uzyskanej z thread::get_id(). Ewentualnie, jak zasugerowano w komentarzach, możesz użyć zmiennej thread_local, jeśli potrzebujesz dostępu tylko do nazwy z wątku.

Jeśli nie potrzebujesz przenośności, możesz pobrać bazową wersję pthread_t z thread::native_handle() i wykonać dowolne, zależne od platformy, operacje, które Ci się spodobają. Należy pamiętać, że _np dla funkcji nazewnictwa nici oznacza "nie posix", więc nie gwarantują, że będą dostępne we wszystkich implementacjach pthreads.

+2

" mapy nazw, pod kluczem identyfikatora wątku "- lub magazynu lokalnego wątku? Zakładając, że debugowanie, które robisz, jest zawsze tylko wewnątrz wątku, którego nazwę chcesz oczywiście znać. –

+1

Jeśli chodzi o projekt, aby zawinąć tę ideę, możesz rozważyć użycie ThreadFactory w swojej aplikacji, której celem jest rejestrowanie wątków po utworzeniu i/lub streszczenie wszystkich potrzebnych "# ifdef", jeśli chcesz użyj prekompilatora, aby wybrać kod specyficzny dla platformy. – Dennis

+7

Cały punkt nazywania wątków ma ułatwić debugowanie, ponieważ debugger będzie pokazywał nazwę wątku, więc utrzymywanie wewnętrznej nazwy niektórych nazw jest bezsensowne ... –

9

Możesz użyć std::thread::native_handle, aby uzyskać zdefiniowany wątek implementacji underlayingu. Nie ma w tym żadnej standardowej funkcji.

Możesz znaleźć przykład here.

3

W systemie Windows [debugger] można z łatwością użyć metody "normalnej"; http://msdn.microsoft.com/en-gb/library/xcb2z8hs.aspx

Wystarczy ID wątku, który można uzyskać poprzez

#include <windows.h> 
DWORD ThreadId = ::GetThreadId(static_cast<HANDLE>(mThread.native_handle())); 
+0

To prawdopodobnie zadziała, ale nie jest to ogólne rozwiązanie w języku C++, a zatem rozwiązanie wieloplatformowe. Dzięki za sugestię i tak. –

+2

Och, to na pewno tylko okna, ale nikt nie powiedział ci, jak ustawić go w oknach. (I działa, ja go używam :) –

15

próbą tworzenia otoki do czynienia z wielu dystrybucji Linksa jak i Windows. W razie potrzeby edytuj.

#ifdef _WIN32 
#include <windows.h> 
const DWORD MS_VC_EXCEPTION=0x406D1388; 

#pragma pack(push,8) 
typedef struct tagTHREADNAME_INFO 
{ 
    DWORD dwType; // Must be 0x1000. 
    LPCSTR szName; // Pointer to name (in user addr space). 
    DWORD dwThreadID; // Thread ID (-1=caller thread). 
    DWORD dwFlags; // Reserved for future use, must be zero. 
} THREADNAME_INFO; 
#pragma pack(pop) 


void SetThreadName(uint32_t dwThreadID, const char* threadName) 
{ 

    // DWORD dwThreadID = ::GetThreadId(static_cast<HANDLE>(t.native_handle())); 

    THREADNAME_INFO info; 
    info.dwType = 0x1000; 
    info.szName = threadName; 
    info.dwThreadID = dwThreadID; 
    info.dwFlags = 0; 

    __try 
    { 
     RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); 
    } 
    __except(EXCEPTION_EXECUTE_HANDLER) 
    { 
    } 
} 
void SetThreadName(const char* threadName) 
{ 
    SetThreadName(GetCurrentThreadId(),threadName); 
} 

void SetThreadName(std::thread* thread, const char* threadName) 
{ 
    DWORD threadId = ::GetThreadId(static_cast<HANDLE>(thread->native_handle())); 
    SetThreadName(threadId,threadName); 
} 

#else 
void SetThreadName(std::thread* thread, const char* threadName) 
{ 
    auto handle = thread->native_handle(); 
    pthread_setname_np(handle,threadName); 
} 


#include <sys/prctl.h> 
void SetThreadName(const char* threadName) 
{ 
    prctl(PR_SET_NAME,threadName,0,0,0); 
} 

#endif 
+1

tylko po to, aby wyjaśnić część Windows tego jest z https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx – BillyT2

+0

W systemie Windows, możesz również użyć interfejs API SetThreadDescription(): http://stackoverflow.com/a/41446477/434413. Jest to nowy oficjalny interfejs API, który jest używany w nowszych narzędziach MS (metoda pokazana w tej odpowiedzi to stara metoda, która działa tylko w przypadku procesów uruchomionych w debugerze Visual Studio w momencie, gdy wyjątek jest rzucany). –

+0

Uwaga: Kod systemu Windows z RaiseException jest przechwytywany w czasie rzeczywistym dzięki debuggerowi. To znaczy. jeśli RaiseException raz na początku wątku i dołączyć później debugger, nie będzie znać nazwę wątku. – Sergey

2

ja widziałem to zrobić zarówno w systemie sprzed C++ 11 (gdzie w zasadzie wynalazł własną klasę wątku, który był bardzo podobny do std :: thread) iw jednym pisałem dość niedawno.

Zasadniczo pula naprawdę stawia std :: thread 2 layers down - masz klasę PoolThread, która zawiera std :: thread plus metadane, takie jak nazwa, ID, itd. Oraz strukturę kontrolną, która łączy ją z jej kontrolowanie puli i samego ThreadPool. Chcesz użyć puli wątków w większości kodu z gwintami z kilku powodów:
1) Możesz ukryć wszystkie wyraźne "odłączyć", "dołączyć", rozpocząć wątek na konstrukcji std :: thread, itp. Od użytkowników. To daje DUŻO bezpieczniejszy kod czyszczący &.
2) Lepsze zarządzanie zasobami: zbyt wiele wątków obniży wydajność nawet o więcej niż za mało. Dobrze zbudowany basen może robić zaawansowane rzeczy, takie jak automatyczne równoważenie obciążenia i czyszczenie zawieszonych lub zakleszczonych wątków.
3) Ponowne użycie wątku: std :: thread sam w sobie jest najłatwiejszy w użyciu, uruchamiając każde równoległe zadanie we własnym wątku. Ale tworzenie wątku jest bardzo kosztowne i może łatwo zepsuć zwiększenie prędkości z przetwarzania równoległego, jeśli nie jesteś ostrożny. Dlatego zwykle bardziej sensowne jest posiadanie wątków puli, które pobierają zadania robocze z kolejki i kończą tylko po otrzymaniu sygnału.
4) Obsługa błędów: std :: thread to tylko kontekst wykonania. Jeśli zadanie, które uruchamiasz, generuje nieobsługiwany wyjątek lub STD :: wątek ITSELF nie powiedzie się, proces się właśnie zawiesza.Aby wykonać wielowątkowość odporną na uszkodzenia, potrzebujesz puli lub czegoś podobnego, co może szybko przechwycić takie rzeczy i przynajmniej emitować znaczące komunikaty o błędach, zanim proces się zakończy.

+4

W odniesieniu do punktu 2: Jeśli dodasz logikę do swojego programu do zawieszonych lub zaklejonych wątków, po prostu próbujesz ukryć błędy. Zalecam zamiast tego naprawić błąd. Coś podobnego idzie do punktu 4: Jeśli otrzymasz nieobsługiwany wyjątek na najwyższym poziomie wątku, masz fatalny błąd w kodzie. Ponownie, priorytetem powinno być naprawienie błędu, a nie "z gracją" poradzenie sobie z sytuacją. – cmaster

Powiązane problemy