c ++ 11 tiene la posibilidad de obtener la identificación del hilo actual, pero no se puede convertir en un tipo entero:
cout<<std::this_thread::get_id()<<endl;
salida: 139918771783456
cout<<(uint64_t)std::this_thread::get_id()<<endl;
error: conversión no válida del tipo 'std :: thread :: id' para escribir 'uint64_t' lo mismo para otros tipos: conversión no válida del tipo 'std :: thread :: id' para escribir 'uint32_t'
Realmente no quiero hacer una conversión de punteros para obtener la identificación del hilo entero. ¿Existe alguna forma razonable (estándar porque quiero que sea portátil) de hacerlo?
c++
multithreading
c++11
NoSenseEtAl
fuente
fuente
operator<<
parece manejar bien).thread::id
no se represente como un número entero. La página a la que enlaza utiliza una matriz, indexada por ID de hilo. ¿Ha considerado usar unmap<thread::id, int>
en su lugar? Luego, puede utilizar los operadores relacionales ya definidos para laid
clase sin realizar ninguna conversión. El estándar también definehash<thread::id>
, por lo que también puede usar los contenedores desordenados.Respuestas:
La solución portátil es pasar sus propios ID generados al hilo.
int id = 0; for(auto& work_item : all_work) { std::async(std::launch::async, [id,&work_item]{ work_item(id); }); ++id; }
El
std::thread::id
tipo debe usarse solo para comparaciones, no para aritmética (es decir, como dice en la lata: un identificador ). Incluso su representación de texto producida por nooperator<<
está especificada , por lo que no puede confiar en que sea la representación de un número.También puede usar un mapa de
std::thread::id
valores para su propia identificación y compartir este mapa (con la sincronización adecuada) entre los subprocesos, en lugar de pasar la identificación directamente.fuente
Solo necesitas hacer
std::hash<std::thread::id>{}(std::this_thread::get_id())
para conseguir un
size_t
.Desde cppreference :
fuente
std::hash<std::thread::id>()(std::this_thread::get_id())
, ¿no?Otra identificación (¿idea? ^^) sería usar cadenas de cadenas:
std::stringstream ss; ss << std::this_thread::get_id(); uint64_t id = std::stoull(ss.str());
Y use try catch si no desea una excepción en caso de que las cosas salgan mal ...
fuente
std::thread::id
imprima como caracteres que componen un número entero de la misma manera que no se garantiza que la identificación del hilo esté representada internamente por un número entero.std::thread::id
como tipo en lugar de un número entero, para eso existe. Y no reinterprete su representación de cadena como dígitos que forman un número. Trátelo como opaco o como salida de depuración / registro.Una idea sería usar el almacenamiento local de subprocesos para almacenar una variable, sin importar el tipo, siempre que cumpla con las reglas del almacenamiento local de subprocesos, luego usar la dirección de esa variable como su "ID de subproceso". Obviamente, cualquier arithemética no tendrá sentido, pero será un tipo integral.
Para la posteridad:
pthread_self()
devuelvepid_t
ay es posix. Esto es portátil para alguna definición de portátil.gettid()
, es casi seguro que no es portátil, pero devuelve un valor compatible con GDB.fuente
pthread_self()
en realidad devuelve unpthread_t
, que es opaco (a diferencia depid_t
(devuelto porgettid()
) que, aunque también es específico de la plataforma, aparentemente es un número entero, al menos). Pero +1 para el primer bit, ¡resolvió mi problema!Realmente no sé qué tan rápido es esto, pero esta es la solución que logré crear:
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;
Nuevamente, estoy empezando a pensar que obtener un puntero a la estructura y convertirlo en unsigned int o uint64_t es la respuesta ... EDITAR:
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 para evitar problemas infernales :) Reescribir es fácil en comparación con la búsqueda de este tipo de error. :)
fuente
hash
función, mucho menos si la% .std::this_thread::get_id()
! Pero probablemente no lo necesite. Un par de hilos compartidos entre sí no crea el mismo problema masivo que cada hilo compartido con todos los demás hilos. Algo comoconst size_t N_COUNTERS = 128; struct Counter { std::atomic<int> counter; char pad[CACHE_LINE_SIZE - sizeof(atomic<int>); } counters[N_COUNTERS];
probablemente esté bien. (Un bloqueo atómico o de giro para una sincronización muy ligera.)atomic<int>
lugar deint
es una desaceleración dramática incluso sin contención.thread::native_handle()
devuelvethread::native_handle_type
, que es un typedef delong unsigned int
.Si el subproceso se construye por defecto, native_handle () devuelve 0. Si hay un subproceso del sistema operativo adjunto, el valor de retorno es distinto de cero (es pthread_t en POSIX).
fuente
std::thread::native_handle_type
es un typedeflong unsigned
? En 30.3.1 / 1 solo podemos vertypedef implementation-defined native_handle_type; // See 30.2.3
De esta forma, debería funcionar:
std::stringstream ss; ss << std::this_thread::get_id(); int id = std::stoi(ss.str());
Recuerde incluir el flujo de la biblioteca
fuente
std::stringstream
, puede usarlooperator >>
para convertirlo a int. De hecho, preferiríauint64_t
como tipo de enid
lugar deint
si estoy seguro de queid
es integral.Una razón clave para no usar thread :: get_id () es que no es único en un solo programa / proceso. Esto se debe a que la identificación se puede reutilizar para un segundo hilo, una vez que finaliza el primer hilo.
Esto parece una característica horrible, pero es lo que está en c ++ 11.
fuente
depende de para qué quieres usar el thread_id; puedes usar:
std::stringstream ss; ss << std::this_thread::get_id(); uint64_t id = std::stoull(ss.str());
Esto generará una identificación única dentro de su proceso; pero hay una limitación: si lanza varias instancias del mismo proceso y cada una de ellas escribe sus ID de subproceso en un archivo común, la unicidad del thread_id no está garantizada; de hecho, es muy probable que tenga superposiciones. En este caso, puede hacer algo como:
#include <sys/time.h> timespec ts; clock_gettime(CLOCK_REALTIME, &ts); uint64_t id = (ts.tv_sec % 1000000000) * 1000000000 + ts.tv_nsec;
ahora se le garantizan identificadores de hilo únicos en todo el sistema.
fuente
operator<<
puede imprimir cualquier cosa , es incorrecto asumir que siempre imprimirá un número entero.Otra alternativa:
#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; }
El código generado para esta función por g ++ en x86 de 64 bits es simplemente:
_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
Es decir, una sola rama sin ninguna sincronización que se predecirá correctamente excepto la primera vez que llame a la función. Después de eso, solo un único acceso a la memoria sin sincronización.
fuente
thread_local
ya describe la duración del almacenamientotid
. Elstatic
dethread_counter
es porque no quiere exponer que, fuera de esta unidad de compilación.0
es una identificación válida, es un buen punto y se puede arreglar usando preincrement en su lugar. Cambiaré la respuesta para hacer eso.Quizás esta solución sea útil para alguien. Llámalo im primera vez
main()
. Advertencia:names
crece indefinidamente.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]; }
fuente