menu

hjk41的日志

Avatar

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, &param);

                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;
}

评论已关闭