When Is Posix Thread Cancellation Not Immediate

When is POSIX thread cancellation not immediate?

The meaning is just what it says: It's not guaranteed to happen instantly. The reason for this is that a certain "liberty" for implementation details is needed and accounted for in the standard.

For example under Linux/NPTL, cancellation is implemented by sending signal nr. 32. The thread is cancelled when the signal is received, which usually happens at the next kernel-to-user switch, or at the next interrupt, or at the end of the time slice (which may accidentially be immediately, but usually is not). A signal is never received while the thread isn't running, however. So the real catch here is actually that signals are not necessarily received immediately.

If you think about it, it isn't even possible to do it much different, either. Since you can phtread_cleanup_push some handlers which the operating system must execute (it cannot just blast the thread out of existence!), the thread must necessarily run to be cancelled. There is no guarantee that any particular thread (including the one you want to cancel) is running at the exact time you cancel a thread, so there can be no guarantee that it is cancelled immediately.

Except of course, hypothetically, if the OS was implemented in a way as to block the calling thread and schedule the to-be-cancelled thread so it executes its handlers, and only unblocks pthread_cancel afterwards. But since pthread_cancel isn't specified as blocking, this would be an utterly nasty surprise. It would also be somewhat inacceptable because of interfering wtih execution time limits and scheduler fairness.

So, either your cancel type is "disable", then nothing happens. Or, it is "enable", and the cancel type is "deferred", then the thread cancels when calling a function that is listed as cancellation point in pthreads(7).

Or, it is "asynchronous", then as stated above, the OS will do "something" to cancel the thread as soon as it deems appropriate -- not at a precise, well-defined time, but "soon". In the case of Linux, by sending a signal.

Why is the thread not waiting for the cancellation point in deferred mode?

I exepected thread will be cancelled when testcancel called,

This expectation is not correct.

From the phread_cancel spec

Deferred cancelability means that cancellation will be delayed until the thread next calls a function that is a cancellation point.

There is also a link included to check what a cancellation point is:

The following functions are required to be cancellation points by POSIX.1-2001 and/or POSIX.1-2008:


...
pthread_testcancel()
...
sleep()
...

Each of them will make your thread respond to cancellation.

This means, also this assumption is not fully correct:

but it cancelling immediately with a changing cancelstate to enable.

Instead your thread is cancelled as soon as it calls sleep in the same iteration when it sets cancel state to enabled. (BTW: Cancel type is deferred by default)

You seem to expect that the thread only checks whether it is cancelled, when it actively queries for cancel state. I don't think this can be done using pthread_cancel.
Instead you need to introduce some communication mechanism (maybe via sockets) to tell the thread that it shall terminate itself.

pthread cancellation activation time

From the docs:

The cancellation processing in the target thread shall run
asynchronously with respect to the calling thread returning from
pthread_cancel().

So pthread_cancel can return before the cancellation happens, meaning your assumption is wrong.

Instead of using pthread_cancel you may consider the more popular and arguably safer method (risk of failure with pthread_cancel) of using a cancel flag and/or condition variables to signal when the function actually ends.

How will pthread_cancel() respond when the cancellation request is queued?

pthread_cancel() will never block. It will also not tell you, whether the thread was successfully cancelled.

In mode deferred: It just sets a flag (a cancel request) which the thread in question has to actively query (potentially implicitly in system calls) and then the thread will exit cooperatively.

In mode asynchronous: The thread will be cancelled at any point in time (usually immediately). This is only safe in pure CPU-bound loops, not calling any system or library function, not even allocating memory directly or indirectly. Note that this is also not safe if the thread is synchronizing with other threads using mutexes or other related thread primitives, as cancelling the thread will leave all mutexes in an undefined state.

In short: Cancelling asynchronously is generally unsafe, unclean by design and should generally be avoided. There are only very few use cases where this can be used in a clean way (for example 100% CPU bound code communicating with other threads only through acquire/release semantics (lock free)).

Is pthread_setcancelstate function a cancellation point when enabling cancelability

Since pthread_setcancelstate is not permitted to be a cancellation point and cancellation is deferred until a cancellation point, the thread cannot be cancelled until the next cancellation point.

pthread_cancel and cancellation point

To have a "cancellation point" you need to use pthread_setcancelstate() to disable cancellation at the start of your thread function and then enable it when you want. When a new thread is spawned, it has the cancel state "enabled" meaning it can be canceled immediately at any time.

Perhaps more to the point, you probably shouldn't use pthread_cancel() at all. For more on that, see here: Cancelling a thread using pthread_cancel : good practice or bad

how the child POSIX thread is canceled

What's happening is that your loop contains at least one cancellation point, sleep (and possibly two, since printf is an optional cancellation point).

Being a cancellation point means the function contains logic similar to:

if (thread_local_cancellation_flag) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED);
pthread_exit(PTHREAD_CANCELED);
}

In reality, however, it's a little bit more complicated, because if the cancellation request arrives while the function is "waiting" or "blocking" for some event to take place (like sleep time to expire, or input from a socket), it must be acted upon. Thus some sort of asynchronous delivery mechanism is required, and the typical implementation is to use signals for this, but it's actually extremely difficult to get right, and popular implementations don't do so well. For some ugly corner cases in glibc which other implementations probably share, see this bug report:

http://sourceware.org/bugzilla/show_bug.cgi?id=12683

In your case, what's almost surely happening is that the cancellation request arrives (via a signal) while the thread is waiting in sleep, and a signal handler runs, determines that it's in the middle of a cancellable operation, and acts on the cancellation request.

will setting pthread_canelState to PTHREAD_CANCEL_DISABLE queue up the cancellation requests?

POSIX threads controls thread cancellation by a combination of two binaries variables:
cancellation STATE and cancellation TYPE. The associated functions are pthread_setcancelstate() and pthread_setcanceltype() accordingly.
When the STATE is set to disabled, the cancellation request is ignored.
It is not thrown out, it is suspended (or as you correctly wrote - "queued"), until the STATE is set back to enabled. Since the state is enabled, the OS starts the cancellation process according to the cancellation type. If you have a code that must be executed before a thread is cancelled (e.g. memory de-allocation etc.), you may set the thread cancellation state to disabled, before entering the code, and enable the cancellation exiting the code. The second question is how and when the thread is really stopped (cancelled). The the cancellation type answers this question. If the type is set to (not recommended) asynchronous, the cancellation may occur at the nearest instruction. If the type is set to the default deferred cancellation, the cancellation will occur at the next "cancellation point", a POSIX function that checks thread cancellation status and terminates the thread.

Cancelling a thread using pthread_cancel : good practice or bad

In general thread cancellation is not a really good idea. It is better, whenever possible, to have a shared flag, that is used by the threads to break out of the loop. That way, you will let the threads perform any cleanup they might need to do before actually exiting.

On the issue of the threads not actually cancelling, the POSIX specification determines a set of cancellation points ( man 7 pthreads ). Threads can be cancelled only at those points. If your infinite loop does not contain a cancellation point you can add one by calling pthread_testcancel. If pthread_cancel has been called, then it will be acted upon at this point.



Related Topics



Leave a reply



Submit