3

I was testing the behavior of how pthread_cancel works.

#include<pthread.h>
#include<unistd.h>
#include<iostream>
using namespace std;
int retval=70;
void* tf(void*arg){
    int oldstate;
    int i=0;
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
    while(true){
        cout<<"sleep 1"<<endl;
        sleep(1);
        ++i;
        if(i==5){//response to last pthread_cancel()?
            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
        }
    }
    return NULL;
}
int main(){
    pthread_t tid;
    pthread_create(&tid,NULL,tf,NULL);
    sleep(2);
    pthread_cancel(tid);//not responded until "PTHREAD_CANCEL_ENABLE"?
    cout<<"cancel thread"<<endl;
    pthread_join(tid,NULL);
    return 0;
}

I expected that

(1) when cancallation is disabled, any call to pthread_cancel will be ignored but the call shall be remembered

(2) until the cancellation is enabled: it will check if there's previous call to pthread_cancel, and if yes, a cancellation is done.

sleep 1
sleep 1
cancel thread
sleep 1
sleep 1
sleep 1
sleep 1

But on my linux server, it prints:

sleep 1
sleep 1
cancel thread
sleep 1
sleep 1
sleep 1
FATAL: exception not rethrown
sleep 1
Aborted (core dumped)

Just having no idea what actuall happened, and how the Fatal exception is throw? I should have some wrong understandings. Need your suggestions!

Community
  • 1
  • 1
Hind Forsum
  • 9,717
  • 13
  • 63
  • 119

2 Answers2

2

Thread cancellation points and C++ do not go well with each other. Think of what would happen with local variables in the thread stack when the thread is cancelled, will their destructors be called.

Historically, there has been some debate about this, and many pthread implementations chose differently. Some would even implement the cancellation with the same mechanism as a C++ exception, so that the stack will be nicely unwound. But then, a well placed catch will mess things around...

But then, pthread_cancel is a POSIX construction, and thus is only well defined for C.

That said, compilers try to do their best. In your case, it is probably a bug in your compiler or some library (you don't say what compiler version and what compiler commands you are using...). Your code works fine for me (GCC 7.1 and Clang 4.0.1).

However if I add a try/catch like this, it fail just like yours:

void* tf(void*arg) {
  try {
      //your code
  } catch (...) {
      return NULL;
  }
}

If however, I rethrow the exception at the end of the catch it will work fine again:

void* tf(void*arg) {
  try {
      //your code
  } catch (...) {
      throw;
  }
}

Which proves that in my C++ compiler pthread_cancel uses the same mechanism as C++ exceptions. My guess is that when the thread is cancelled in C++ mode, it throws an internal exception, and it expects to catch it at the parent of the thread function. But if you return normally from a thread function, when that thread has been cancelled, then this message is shown.

And since you are not doing anything of this, there are several explanations:

  • You are using a compiler that does not support C++ and pthread cancellation.
  • A bug in your version of the compiler/library.
  • You are mixing different versions of the compiler/library. Or maybe you are mixing C and C++ libraries.

PS 1: I checked adding a local variable with a non trivial destructor to the thread function, and I confirm that the destructor is called when the thread finishes.

PS 2: I checked calling pthread_exit() from the thread function, without cancellations, and the local destructors are also called. If I do the try/catch(...) around pthread_exit() it fails with the same FATAL: exception not rethrown. So pthread_exit() and pthread_cancel() use the same underlying mechanism.

PS 3: All that looks very nice, but thread cancellation can still occur at any point: if the thread cancellation happens in the middle of a cout.operator<<() then any further writing to that stream (from the local destructors for example) will not work at all.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
1

It is working fine on my PC running Linux.

$ g++ try.cc -o try -lpthread
$ ./try
sleep 1
sleep 1
cancel thread
sleep 1
sleep 1
sleep 1
sleep 1
$ 
kjohri
  • 1,166
  • 11
  • 10