c ++ 11 ma możliwość pobrania bieżącego id wątku, ale nie można go rzutować na typ całkowity:
cout<<std::this_thread::get_id()<<endl;
wyjście: 139918771783456
cout<<(uint64_t)std::this_thread::get_id()<<endl;
błąd: nieprawidłowe rzutowanie z typu „std :: thread :: id” do typu „uint64_t” to samo dla innych typów: nieprawidłowe rzutowanie z typu „std :: thread :: id” do typu „uint32_t”
Naprawdę nie chcę rzucać wskaźników, aby uzyskać identyfikator wątku będący liczbą całkowitą. Czy jest jakiś rozsądny sposób (standardowy, ponieważ chcę, aby był przenośny), aby to zrobić?
c++
multithreading
c++11
NoSenseEtAl
źródło
źródło
operator<<
wydaje się dobrze obsługiwać).thread::id
ogóle nie jest reprezentowana jako liczba całkowita. Strona, do której prowadzi łącze, korzysta z tablicy indeksowanej według identyfikatora wątku. Czy rozważałeś użyciemap<thread::id, int>
zamiast tego? Następnie możesz użyć operatorów relacyjnych już zdefiniowanych dlaid
klasy bez wykonywania żadnych konwersji. Norma również definiujehash<thread::id>
, więc możesz używać również nieuporządkowanych kontenerów.Odpowiedzi:
Przenośnym rozwiązaniem jest przekazanie własnych wygenerowanych identyfikatorów do wątku.
int id = 0; for(auto& work_item : all_work) { std::async(std::launch::async, [id,&work_item]{ work_item(id); }); ++id; }
std::thread::id
Typ ma być wykorzystywane do porównań, nie dla arytmetyki (czyli jak jest napisane na puszce: AN identyfikatora ). Nawet jego reprezentacja tekstowa utworzona przezoperator<<
jest nieokreślona , więc nie można polegać na tym, że jest reprezentacją liczby.Możesz także użyć mapy
std::thread::id
wartości na swój własny identyfikator i udostępnić tę mapę (z odpowiednią synchronizacją) między wątkami, zamiast przekazywać identyfikator bezpośrednio.źródło
Po prostu musisz to zrobić
std::hash<std::thread::id>{}(std::this_thread::get_id())
aby dostać
size_t
.Od cppreference :
źródło
std::hash<std::thread::id>()(std::this_thread::get_id())
, prawda?Innym id (pomysł? ^^) byłoby użycie stringstreams:
std::stringstream ss; ss << std::this_thread::get_id(); uint64_t id = std::stoull(ss.str());
I użyj try catch, jeśli nie chcesz mieć wyjątku na wypadek, gdyby coś poszło nie tak ...
źródło
std::thread::id
wydrukowany jako znaki składające się na liczbę całkowitą w taki sam sposób, w jaki nie ma gwarancji, że identyfikator wątku jest wewnętrznie reprezentowany przez liczbę całkowitą.std::thread::id
jako typu zamiast jakiejś liczby całkowitej, po to istnieje. I nie interpretuj ponownie jego reprezentacji w postaci łańcucha jako cyfr tworzących liczbę. Traktuj je jako nieprzezroczyste lub jako wyjście debugowania / rejestrowania.Jednym z pomysłów byłoby użycie lokalnego magazynu wątków do przechowywania zmiennej - bez względu na typ, o ile jest on zgodny z zasadami lokalnego przechowywania wątków - a następnie użycie adresu tej zmiennej jako „identyfikatora wątku”. Oczywiście żaden arytemetyka nie będzie znaczący, ale będzie typem integralnym.
Dla potomnych:
pthread_self()
zwraca apid_t
i jest posix. To jest przenośne dla niektórych definicji przenośnych.gettid()
, prawie na pewno nie przenośny, ale zwraca wartość przyjazną dla GDB.źródło
pthread_self()
w rzeczywistości zwraca wartośćpthread_t
, która jest nieprzezroczysta (w przeciwieństwie dopid_t
(zwracana przezgettid()
), która, chociaż jest również specyficzna dla platformy, jest najwyraźniej przynajmniej liczbą całkowitą). Ale +1 za pierwszy bit, to rozwiązało mój problem!Naprawdę nie wiem, jak szybko to jest, ale jest to rozwiązanie, które udało mi się gościć:
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;
Znowu zaczynam myśleć, że uzyskanie wskaźnika do struktury i rzutowanie go na unsigned int lub uint64_t jest odpowiedzią ... EDYCJA:
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, aby zapobiec piekielnym problemom :) Przepisywanie jest łatwe w porównaniu do polowania na tego rodzaju błędy. :)
źródło
hash
funkcją, a tym bardziej, jeśli% ją% .std::this_thread::get_id()
! Ale prawdopodobnie tego nie potrzebujesz. Udostępnianie kilku wątków nie stanowi tego samego ogromnego problemu, co każde udostępnianie wątków w każdym innym wątku. Coś jakconst size_t N_COUNTERS = 128; struct Counter { std::atomic<int> counter; char pad[CACHE_LINE_SIZE - sizeof(atomic<int>); } counters[N_COUNTERS];
jest prawdopodobnie w porządku. (Atomic lub spinlock do bardzo lekkiej synchronizacji.)atomic<int>
zamiastint
to dramatyczne spowolnienie, nawet bez rywalizacji.thread::native_handle()
zwracathread::native_handle_type
, co jest typedef tolong unsigned int
.Jeśli wątek jest zbudowany domyślnie, native_handle () zwraca 0. Jeśli jest do niego dołączony wątek systemu operacyjnego, wartość zwracana jest różna od zera (jest to pthread_t w POSIX).
źródło
std::thread::native_handle_type
jest to typedeflong unsigned
? W 30.3.1 / 1 możemy zobaczyć tylkotypedef implementation-defined native_handle_type; // See 30.2.3
W ten sposób powinno działać:
std::stringstream ss; ss << std::this_thread::get_id(); int id = std::stoi(ss.str());
Pamiętaj o dołączeniu strumienia biblioteki
źródło
std::stringstream
, możesz użyć jegooperator >>
do konwersji na int. Właściwie wolałbymuint64_t
jako typid
zamiast tego,int
czy jestem pewien, żeid
jest całka.Głównym powodem, dla którego nie należy używać funkcji thread :: get_id () jest to, że nie jest ona unikalna w pojedynczym programie / procesie. Dzieje się tak, ponieważ identyfikator może zostać ponownie użyty dla drugiego wątku, po zakończeniu pierwszego wątku.
Wydaje się, że to okropna funkcja, ale to, co jest w C ++ 11.
źródło
zależy to od tego, do czego chcesz użyć thread_id; możesz użyć:
std::stringstream ss; ss << std::this_thread::get_id(); uint64_t id = std::stoull(ss.str());
Spowoduje to wygenerowanie unikalnego identyfikatora podczas przetwarzania; ale jest ograniczenie: jeśli uruchamiasz kilka instancji tego samego procesu i każdy z nich zapisuje swoje identyfikatory wątków do wspólnego pliku, unikalność thread_id nie jest gwarantowana; w rzeczywistości jest bardzo prawdopodobne, że będziesz się pokrywać. W takim przypadku możesz zrobić coś takiego:
#include <sys/time.h> timespec ts; clock_gettime(CLOCK_REALTIME, &ts); uint64_t id = (ts.tv_sec % 1000000000) * 1000000000 + ts.tv_nsec;
teraz masz zagwarantowane unikalne identyfikatory wątków w całym systemie.
źródło
operator<<
może wydrukować wszystko , błędem jest zakładać, że zawsze wypisze liczbę całkowitą.Inna alternatywa:
#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; }
Wygenerowany kod dla tej funkcji przez g ++ w 64-bitowej architekturze x86 to po prostu:
_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
To znaczy pojedyncza gałąź bez synchronizacji, która będzie poprawnie przewidziana, z wyjątkiem pierwszego wywołania funkcji. Potem tylko jeden dostęp do pamięci bez synchronizacji.
źródło
thread_local
już opisuje czas przechowywaniatid
.static
Zathread_counter
to, bo nie chce narażać go na zewnątrz tej jednostki kompilacji.0
jest to ważny identyfikator, który jest dobrym punktem i można go zamiast tego naprawić za pomocą preinkrementu. Zmienię odpowiedź, żeby to zrobić.Może to rozwiązanie komuś pomoże. Nazwij to po raz pierwszy im
main()
. Ostrzeżenie:names
rośnie w nieskończoność.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]; }
źródło