Change pthread cancel type of another thread?
What I want to accomplish is that a main thread tries a normal deferred cancel first on a worker thread (executing code that is for my purposes a black box), and then if the thread is 开发者_Python百科still running after a timeout (pthread_timedjoin_np()
), I want to do an asynchronous cancel. The problem I'm having is that pthread_setcanceltype()
is only for the calling thread. Is there some workaround or hack that will let me do this? I want to avoid using signals as at least under Linux it seems that an asynchronous cancel will still execute C++ destructors of the thread's objects, which is important for me.
There are some cases, when pthread_setcanceltype()
must actually do a cancel (see source below). So, this is a reason, why there is no pthread_setcanceltype_for_thread()
. The actual cancel type is the field in pthread struct, which must be changed atomically.
ftp://sources.redhat.com/pub/glibc/snapshots/glibc-latest.tar.bz2/glibc-20090518/nptl/pthread_setcanceltype.c
__pthread_setcanceltype (type, oldtype)
int type;
int *oldtype;
{
volatile struct pthread *self;
self = THREAD_SELF;
int oldval = THREAD_GETMEM (self, cancelhandling);
while (1)
{
int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS
? oldval | CANCELTYPE_BITMASK
: oldval & ~CANCELTYPE_BITMASK);
/* Store the old value. */
if (oldtype != NULL)
*oldtype = ((oldval & CANCELTYPE_BITMASK)
? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED);
/* Update the cancel handling word. This has to be done
atomically since other bits could be modified as well. */
int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
oldval);
if (__builtin_expect (curval == oldval, 1))
{
if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
{
THREAD_SETMEM (self, result, PTHREAD_CANCELED);
__do_cancel (); // HERE THE CANCELLING
}
break;
}
/* Prepare for the next round. */
oldval = curval;
}
return 0;
}
strong_alias (__pthread_setcanceltype, pthread_setcanceltype)
If you have a big need to change canceltype externally, you can hack the library and set the field directly.
PS: for NPTL (current implementation of pthreads in glibc on Linux)
the easiest way to see how to get struct pthread
from int pthread_t is ... pthread_join:
pthread_join (pthread_t threadid, thread_return)
{
struct pthread *pd = (struct pthread *) threadid;
精彩评论