c ++ 11 имеет возможность получить текущий идентификатор потока, но он не может быть приведен к целочисленному типу:
cout<<std::this_thread::get_id()<<endl;
вывод: 139918771783456
cout<<(uint64_t)std::this_thread::get_id()<<endl;
ошибка: недопустимое приведение из типа 'std :: thread :: id' к типу 'uint64_t', то же самое для других типов: недопустимое приведение из типа 'std :: thread :: id' для типа 'uint32_t'
Я действительно не хочу выполнять приведение указателя, чтобы получить целочисленный идентификатор потока. Есть ли какой-нибудь разумный способ (стандартный, потому что я хочу, чтобы он был портативным) сделать это?
c++
multithreading
c++11
NoSenseEtAl
источник
источник
operator<<
похоже, справляется нормально).thread::id
вообще не будет представлено в виде целого числа. Страница, на которую вы ссылаетесь, использует массив, индексированный по идентификатору потока. Вы не думали использоватьmap<thread::id, int>
вместо этого? Затем вы можете использовать операторы отношения, уже определенные дляid
класса, без каких-либо преобразований. Стандарт также определяетhash<thread::id>
, поэтому вы также можете использовать неупорядоченные контейнеры.Ответы:
Переносимое решение - передать ваши собственные сгенерированные идентификаторы в поток.
int id = 0; for(auto& work_item : all_work) { std::async(std::launch::async, [id,&work_item]{ work_item(id); }); ++id; }
std::thread::id
Тип должен использоваться для сравнения, а не для арифметической (то есть , как он говорит на баллончике: идентификатор ). Даже его текстовое представление, созданное с помощью,operator<<
не определено , поэтому вы не можете полагаться на то, что это представление числа.Вы также можете использовать карту
std::thread::id
значений для своего собственного идентификатора и совместно использовать эту карту (с надлежащей синхронизацией) между потоками вместо передачи идентификатора напрямую.источник
Вам просто нужно сделать
std::hash<std::thread::id>{}(std::this_thread::get_id())
чтобы получить
size_t
.Из cppreference :
источник
std::hash<std::thread::id>()(std::this_thread::get_id())
, не так ли?Другой идентификатор (идея? ^^) - использовать строковые потоки:
std::stringstream ss; ss << std::this_thread::get_id(); uint64_t id = std::stoull(ss.str());
И используйте try catch, если вы не хотите исключения в случае, если что-то пойдет не так ...
источник
std::thread::id
печататься как символы, составляющие целое число, во многом так же, как не гарантируется, что идентификатор потока внутренне представлен целым числом.std::thread::id
как тип вместо целого числа, для чего он существует. И не интерпретируйте его строковое представление заново как цифры, составляющие число. Рассматривайте его как непрозрачный или как вывод отладки / ведения журнала.Одна из идей - использовать локальное хранилище потока для хранения переменной - неважно, какого типа, если он соответствует правилам локального хранилища потока - а затем использовать адрес этой переменной в качестве «идентификатора потока». Очевидно, что любая арифметика не будет иметь смысла, но это будет цельный тип.
Для потомков:
pthread_self()
возвращает apid_t
и is posix. Это переносимо для некоторого определения переносимости.gettid()
, почти наверняка не переносится, но возвращает дружественное к GDB значение.источник
pthread_self()
фактически возвращает apthread_t
, который является непрозрачным (в отличие отpid_t
(возвращенногоgettid()
), который, хотя и зависит от платформы, по крайней мере, является целым числом). Но +1 для первого бита решил мою проблему!Я действительно не знаю, насколько это быстро, но это решение, которое мне удалось предположить:
const size_t N_MUTEXES=128;//UINT_MAX,not 128 for answer to my original question hash<std::thread::id> h; cout<<h(std::this_thread::get_id())%N_MUTEXES<<endl;
Опять же, я начинаю думать, что получение указателя на структуру и приведение его к unsigned int или uint64_t - это ответ ... EDIT:
uint64_t get_thread_id() { static_assert(sizeof(std::thread::id)==sizeof(uint64_t),"this function only works if size of thead::id is equal to the size of uint_64"); auto id=std::this_thread::get_id(); uint64_t* ptr=(uint64_t*) &id; return (*ptr); } int main() { cout<<std::this_thread::get_id()<<" "<<get_thread_id()<<endl; }
static_assert для предотвращения адских проблем :) Переписать проще, чем выслеживать такого рода ошибки. :)
источник
hash
функцией, тем более, если вы% ее .std::this_thread::get_id()
! Но, вероятно, вам это не нужно. Пара потоков, совместно используемых друг с другом, не создает такой серьезной проблемы, как каждый поток, совместно используемый с каждым другим потоком. Что-то вродеconst size_t N_COUNTERS = 128; struct Counter { std::atomic<int> counter; char pad[CACHE_LINE_SIZE - sizeof(atomic<int>); } counters[N_COUNTERS];
, наверное, нормально. (Атомарная или спин-блокировка для очень легкой синхронизации.)atomic<int>
вместоint
- это резкое замедление даже без разногласий.thread::native_handle()
возвращаетthread::native_handle_type
, который является typedef дляlong unsigned int
.Если поток создан по умолчанию, native_handle () возвращает 0. Если к нему подключен поток ОС, возвращаемое значение не равно нулю (это pthread_t в POSIX).
источник
std::thread::native_handle_type
это typedef дляlong unsigned
? В 30.3.1 / 1 мы можем видеть толькоtypedef implementation-defined native_handle_type; // See 30.2.3
Таким образом должны работать:
std::stringstream ss; ss << std::this_thread::get_id(); int id = std::stoi(ss.str());
Не забудьте включить библиотеку sstream
источник
std::stringstream
, вы можете использовать егоoperator >>
для преобразования в int. На самом деле я бы предпочелuint64_t
как тип,id
а неint
если я уверен, чтоid
это целое.Основная причина не использовать thread :: get_id () заключается в том, что он не уникален для одной программы / процесса. Это потому, что идентификатор может быть повторно использован для второго потока после завершения первого потока.
Это кажется ужасной функцией, но это то, что есть в С ++ 11.
источник
это зависит от того, для чего вы хотите использовать thread_id; вы можете использовать:
std::stringstream ss; ss << std::this_thread::get_id(); uint64_t id = std::stoull(ss.str());
Это сгенерирует уникальный идентификатор внутри вашего процесса; но есть ограничение: если вы запускаете несколько экземпляров одного и того же процесса, и каждый из них записывает свои идентификаторы потока в общий файл, уникальность thread_id не гарантируется; на самом деле очень вероятно, что у вас будут совпадения. В этом случае вы можете сделать что-то вроде:
#include <sys/time.h> timespec ts; clock_gettime(CLOCK_REALTIME, &ts); uint64_t id = (ts.tv_sec % 1000000000) * 1000000000 + ts.tv_nsec;
теперь вам гарантированы уникальные идентификаторы потоков во всей системе.
источник
operator<<
может печатать что угодно , ошибочно полагать, что он всегда будет печатать целое число.Другая альтернатива:
#include <atomic> static std::atomic<unsigned long long> thread_counter; unsigned long long thread_id() { thread_local unsigned long long tid = ++thread_counter; return tid; }
Сгенерированный код для этой функции с помощью g ++ в 64-разрядной версии x86 выглядит так:
_Z9thread_idv: cmp BYTE PTR fs:_ZGVZ9thread_idvE3tid@tpoff, 0 je .L2 mov rax, QWORD PTR fs:_ZZ9thread_idvE3tid@tpoff ret .L2: mov eax, 1 lock xadd QWORD PTR _ZL14thread_counter[rip], rax mov BYTE PTR fs:_ZGVZ9thread_idvE3tid@tpoff, 1 mov QWORD PTR fs:_ZZ9thread_idvE3tid@tpoff, rax ret _ZGVZ9thread_idvE3tid: .zero 8 _ZZ9thread_idvE3tid: .zero 8
Т.е. единственная ветвь без какой-либо синхронизации, которая будет правильно предсказана, за исключением первого вызова функции. После этого всего один доступ к памяти без синхронизации.
источник
thread_local
уже описан срок храненияtid
.static
Дляthread_counter
потому , что вы не хотите , чтобы выставить его за пределами этого модуля компиляции.0
это действительный идентификатор, это хороший момент, и его можно исправить с помощью преинкремента. Для этого я изменю ответ.Может быть, это решение кому-то поможет. Назовите это впервые им
main()
. Предупреждение:names
неограниченно растёт.std::string currentThreadName(){ static std::unordered_map<std::thread::id,std::string> names; static std::mutex mtx; std::unique_lock<std::mutex> lock(mtx); auto id = std::this_thread::get_id(); if(names.empty()){ names[id] = "Thread-main"; } else if(names.find(id) == names.end()){ std::stringstream stream; stream << "Thread-" << names.size(); names[id] = stream.str(); } return names[id]; }
источник