2012-04-12 3 views
38

Новый C++ имеет этот тип std :: thread. Работает как шарм. Теперь я хотел бы дать каждой теме имя для более легкой отладки (например, java). С Pthreads я хотел бы сделать:std :: thread - называет вашу нить

pthread_setname_np(pthread_self(), "thread_name"); 

, но как я могу сделать это с помощью C++ 0x? Я знаю, что он использует pthreads под Linux, но я хотел бы сделать свое приложение переносимым. Это вообще возможно?

+1

В Windows имя потока является свойством отладчика (т. Е. Отслеживается вне самого приложения). В результате у вас нет эквивалента 'pthread_getname_np' – MSalters

ответ

26

Портативный способ сделать это - сохранить карту имен, с помощью идентификатора потока, полученную от thread::get_id(). В качестве альтернативы, как указано в комментариях, вы можете использовать переменную thread_local, если вам нужно только получить доступ к имени из потока.

Если вам не нужна переносимость, тогда вы можете получить базовый pthread_t от thread::native_handle() и делать с ними какие-то специфические для платформы шантажи. Имейте в виду, что _np в функциях именования нитей означает «не posix», поэтому они не гарантируются на всех реализациях pthreads.

+2

« карты имен, с помощью идентификатора потока »или локального хранилища потоков? Предполагая, что отладка, которую вы делаете, происходит только изнутри потока, имя которого вы хотите знать, конечно. –

+1

Что касается дизайна, чтобы обернуть эту идею, вы можете рассмотреть возможность использования ThreadFactory в своем приложении, целью которого является регистрация потоков при создании и/или абстрагировании всех требований '# ifdef', если вы хотите используйте предварительный компилятор для выбора конкретного кода платформы. – Dennis

+7

Весь смысл именования потоков заключается в том, чтобы облегчить отладку, потому что отладчик будет показывать имя потока, поэтому сохранение некоторых карт имен внутри является беспредметным ... –

9

Вы можете использовать std::thread::native_handle, чтобы получить заданную реализацию, лежащую в основе. Для этого нет стандартной функции.

Вы можете найти пример here.

3

Для окон [отладчик] вы можете легко использовать «обычный» метод; http://msdn.microsoft.com/en-gb/library/xcb2z8hs.aspx

Просто нужен идентификатор потока, который вы можете получить с помощью

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

Это, вероятно, будет работать, но это не общий C++ и, следовательно, кроссплатформенное решение. Спасибо, что предложили это в любом случае. –

+2

О, это только окна, но никто на самом деле не сказал вам, как установить его на окна. (И он работает, я использую его :) –

15

попытки сделать обертку для решения многих дистрибутивов Linux, а также Windows. При необходимости отредактируйте.

#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

просто для того, чтобы уточнить часть Windows, это от https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx – BillyT2

+0

В Windows вы также можете использовать API SetThreadDescription(): http://stackoverflow.com/a/41446477/434413. Это новый официальный API, который используется в новых инструментах MS (метод, показанный в этом ответе, является старым способом его выполнения, который работает только для процессов, которые выполняются внутри отладчика Visual Studio во время исключения). –

+0

Примечание: код Windows с функцией RaiseException находится в режиме реального времени с отладчиком. То есть если вы RaiseException один раз при запуске потока и присоедините отладчик позже, он не будет знать имя потока. – Sergey

2

я и видел это сделано в системе существовавшей с ++ 11 (где мы в основном изобрели свой собственный класс Thread, который был очень похож на StD :: нить) и в одном я писал совсем недавно.

В принципе, пул действительно ставит std :: thread 2 слоя вниз - у вас есть класс PoolThread, который содержит метаданные std :: thread plus, такие как его имя, идентификатор и т. Д. И структуру управления, которая связывает ее с ее управляющий пул и сам ThreadPool. Вы хотите использовать пулы потоков в большинстве потоков кода по нескольким причинам:
1) Вы можете скрыть все явные «отсоединение», «объединение», начало потока на std :: thread construction и т. Д. От пользователей. Это дает МНОГО безопаснее & код чистки.
2) Лучшее управление ресурсами: Слишком много потоков будет искажать производительность даже больше, чем слишком мало. Хорошо построенный пул может выполнять расширенные функции, такие как автоматическая балансировка нагрузки и очистка зависающих или заторможенных потоков.
3) Повторное использование потока: std :: thread сам по себе проще всего использовать, выполняя каждую параллельную задачу в своем потоке. Но создание потоков & разрушение дорогое, и вы можете легко повысить скорость при параллельной обработке, если не будете осторожны. Таким образом, обычно имеет смысл иметь пул потоков, которые вытягивают рабочие задачи из очереди и только выходят после получения некоторого сигнала.
4) Обработка ошибок: std :: thread - это просто контекст выполнения. Если задача, которую вы выполняете на ней, выдает исключение без обработки или std :: thread ITSELF завершается с ошибкой, процесс просто сработает прямо там.Чтобы сделать отказоустойчивую многопоточность, вам нужен пул или что-то подобное, что может быстро поймать такие вещи и, по крайней мере, исправить значимые сообщения об ошибках до того, как процесс погибнет.

+4

Что касается вашей точки 2: если вы добавляете логику в свою программу для очистки зависающих или заторможенных потоков, вы просто пытаетесь скрыть ошибки. Я бы рекомендовал исправить ошибку. Что-то похожее на пункт 4: если вы получаете необработанное исключение из верхнего уровня потока, у вас есть фатальная ошибка в вашем коде. Опять же, приоритетом должно быть исправление ошибки, а не «грациозно» справиться с ситуацией. – cmaster

Смежные вопросы