Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a function when thread is exiting in PThreads or Windows

I am creating a C++ library for both Linux (with PThreads) and Windows (with their built-in WinThreads) which can be attached to any program, and needs to have a function called when the thread is exiting, similar to how atexit works for processes.

I know of pthread_cleanup_push and pthread_cleanup_pop for pthreads, but these do not work for me since they are macros that add another lexical scope, whereas I want to declare this function the first time my library is called into, and then allow the program itself to run its own code however it needs to. I haven't found anything similar in Windows whatsoever.

Note that this doesn't mean I want an outside thread to be alerted when the thread stops, or even that I can change the way the thread will be exited, since that is controlled by the program itself, my library is just attached, along for the ride.

So the question is: What is the best way, in this instance, for me to have a function I've written called when the thread closes, in either Windows or Linux, when I have no control over how the thread is created or destroyed?

For example in main program:

void* threadFunc(void* arg)
{
    printf("Hello world!\n");
    return NULL;
}

int main(int argc, char** argv)
{
    int        numThreads = 1;
    pid_t*     pids       = NULL;
    pids     = (pid_t*)     calloc(sizeof(pid_t), numThreads);

    pthread_create(&ntid, NULL, threadFunc, &nVal);
    pthreads[0] = ntid;

    pthread_join(pthreads[0], NULL);
    return 0;
}

In library:

void callMeOnExit()
{
    printf("Exiting Thread!\n");
}

I would want for callMeOnExit to be called when the thread reaches return NULL; in this case, as well as when the main thread reaches the return 0;. Wrapping pthread_exit would work for other cases, and could be a solution, but I'd like a better one if possible.

If anyone has any ideas on how I might be able to do this, that would be great!

like image 739
Dave McGinnis Avatar asked Apr 30 '12 21:04

Dave McGinnis


2 Answers

So after a few code reviews, we were able to find a much more elegant way to do this in Linux, which matches both what Windows does with Fibers (as Neeraj points out) as well as what I expected to find when I started looking into this issue.

The key is that pthread_key_create takes in, as the second argument, a pointer to a destructor, which is called when any thread which has initialized this TLS data dies. I was already using TLS elsewhere per thread, but a simple store into TLS would get you this feature as well to ensure it was called.

like image 103
Dave McGinnis Avatar answered Oct 21 '22 09:10

Dave McGinnis


Change this:

pthread_create(&ntid, NULL, threadFunc, &nVal);

into:

struct exitInformData
{
   void* (CB*)(void*);
   void* data;
   exitInformData(void* (cp*)(void*), void* dp): CB(cp) data(dp) {}
};
pthread_create(&ntid, NULL, exitInform, new exitInformData(&threadFunc, &nVal));

Then Add:

void* exitInform(void* data)
{
    exitInformData* ei = reinterpret_cast<exitInformData*>(data);

    void* r = (ei.CB)(ei.data);   // Calls the function you want.
    callMeOnExit();               // Calls the exit notification.
    delete ei;
    return r;
}
like image 33
Martin York Avatar answered Oct 21 '22 07:10

Martin York