Search code examples
c++linuxpthreadspthread-join

How to cancel a pthread without cancellation point


I use a 3rd-party-library (dcerpc) for my application being a rpc server. Let's say the 3rd party function are in the namespace third.

I call third::listen in a thread, in order to listen for incoming requests.

"Third" provides all the mechanisms to interrupt this listen and properly exit the thread, but either it doesn't work, or I don't do it the correct way. I first try everything with the library tools (demo sample, mail-list, browse the source code to understand...) but with no success.

So I try an alternative: violently kill the listening thread. But third::listen has no cancellation point, I guess.

So this code (I simulate third::listen with listen function above):

void* listen(void*)
{
    cout << "listening for calls...." << endl;

    while (true) {}
    printf ("Server stoppped listening\n");
    return 0;
}


int main()
{

    pthread_t thread = 0;

    int res = pthread_create(&thread, 0, listen, 0);
    cout << "pthread_create res: " << res << endl;

    sleep(1);

    bool isThreadRunning = (pthread_tryjoin_np(thread, 0) != 0);
    cout << "Thread is running: " << isThreadRunning << endl;

    res = pthread_cancel(thread);
    cout << "pthread_cancel res: " << res << endl;

    sleep(1);

    isThreadRunning = (pthread_tryjoin_np(thread, 0) != 0);
    cout << "Thread is running: " << isThreadRunning << endl;

    res = pthread_join(thread, 0);
    cout << "pthread_join res: " << res << endl;

    return 0;
}

will output:

pthread_create res: 0
listening for calls....

Thread is running: 1
pthread_cancel res: 0
Thread is running: 1

and pthread_join(thread, 0) blocks (logic because no cancellation point).

My question: how to kill this thread !!

I tried with signals, but it stops my whole process, not only the thread.

My last try will be to isolate the listening in a dedicated fork process, but in my project context, it's really a pain to fork (that's another story).

Thanks a lot for any help.

Nicolas.


Solution

  • Whether a thread can be cancelled depends on its cancellation state and type. The default state is enabled. So that's fine. But the default type is deferred. That means when you send the thread a cancellation request, it's deferred until it reaches a cancellation point. Since your thread doesn't do anything in the empty loop, it doesn't reach a cancellation point at all. Hence, it doesn't respond to pthread_cancel().

    You can set the cancellation type of the thread to PTHREAD_CANCEL_ASYNCHRONOUS which will typically make the thread exit. Call

    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
    

    before the loop.

    Or you can call one of the functions that's a cancellation point. For example, do fflush(stdout); inside the loop.

    POSIX list a number of functions as cancellation point. See cancellation points for such a list.

    I can't make any comment on the "3rd party" library that doesn't respond to exiting threads with the limited information you have given.