get thread id in pthread
Thread ID starting from 0 is useful when writing multi-threaded program. In OpenMP, you can simply use omp_get_thread_num() to get the current thread ID. But unfortunately, there is no such thing in PTHREAD. Though pthread_self() returns pthread_t, it does not return an ID starting from 0.
The following code is a simple and naive implementation of GetThreadID() in PTHREAD. By wrapping the standard PTHREAD calls, we are able to provide a mechanism to determine the current thread ID. The code basically uses pthread_key, which is provided by PTHREAD to manipulate data on a per-thread basis, so that we can keep a thread ID for every thread, and easily retrieve the information within each thread. For more information, please refer to PTHREAD specification.
Note: the code actually has several flaws, one of them is that CreateThreadWithID() is not thread-safe. This is because it uses a global variable thread_barrier to synchronize with the child process. But if there are more than one thread trying to perform CreateThreadWithID(), there will be race conditions. I will try to come up with a thread-safe version later, but currently, I am satisfied with it. It meets my purpose, in which a master thread creates all the other slaves.
// MyThread.h
struct ThreadParam{
unsigned int id;
void *(*func)(void *);
void * arg;
};
static pthread_key_t thread_key;
static pthread_barrier_t thread_barrier;
static pthread_once_t thread_once=PTHREAD_ONCE_INIT;
void thread_make_key();
void * FakeEntry( void * param );
pthread_t CreateThreadWithID(void *(*func)(void *), void * arg, unsigned int id, const pthread_attr_t * attr);
int ThreadJoin(pthread_t);
unsigned int GetThreadID();
// MyThread.cpp
void thread_make_key(){
pthread_key_create(&thread_key,NULL);
}
void * FakeEntry(void * param){
ThreadParam args=*(ThreadParam *)param;
pthread_barrier_wait(&thread_barrier);
pthread_once(&thread_once, thread_make_key);
pthread_setspecific(thread_key, &args.id);
args.func(args.arg);
};
pthread_t CreateThreadWithID(void *(*func)(void *), void * arg, unsigned int id, const pthread_attr_t * attr){
ThreadParam param;
param.id=id;
param.func=func;
param.arg=arg;
pthread_barrier_init(&thread_barrier, NULL, 2);
pthread_t thread;
pthread_create(&thread, attr, FakeEntry, ¶m);
pthread_barrier_wait(&thread_barrier);
pthread_barrier_destroy(&thread_barrier);
return thread;
}
int ThreadJoin(pthread_t thread){
return pthread_join(thread,NULL);
}
unsigned int GetThreadID(){
return *(unsigned int *)pthread_getspecific(thread_key);
}
// testThread.cpp
#include "MyThread.h"
#include <iostream>
using namespace std;
using namespace HMM_CPU;
const int THREADS=4;
void * foo(void * arg){
*(int *)arg=GetThreadID();
return 0;
}
int main(){
// create threads
pthread_t * threads=new pthread_t[THREADS];
int * ids=new int[THREADS];
for(int i=0;i<THREADS;i++){
threads[i]=CreateThreadWithID(foo, &ids[i], i, NULL);
}
for(int i=0;i<THREADS;i++){
ThreadJoin(threads[i]);
cout<<ids[i]<<endl;
}
delete[] ids;
delete[] threads;
return 0;
}