Under normal circumstances, a thread terminates when it exits normally, either by
returning from its thread function or by calling pthread_exit. However, it is possible
for a thread to request that another thread terminate.This is called canceling a thread.
To cancel a thread, call pthread_cancel, passing the thread ID of the thread to be
canceled. A canceled thread may later be joined; in fact, you should join a canceled
thread to free up its resources, unless the thread is detached (see Section 4.1.5,“Thread
Attributes”).The return value of a canceled thread is the special value given by
PTHREAD_CANCELED.
Often a thread may be in some code that must be executed in an all-or-nothing
fashion. For instance, the thread may allocate some resources, use them, and then deal-locate them.
If the thread is canceled in the middle of this code,
it may not have the opportunity to deallocate the resources,
and thus the resources will be leaked.To
counter this possibility, it is possible for a thread to control whether and when it can
be canceled.
A thread may be in one of three states with regard to thread cancellation.
[]The thread may be asynchronously cancelable.The thread may be canceled at any
point in its execution.
[] The thread may be synchronously cancelable.The thread may be canceled, but not
at just any point in its execution. Instead, cancellation requests are queued, and
the thread is canceled only when it reaches specific points in its execution.
[] A thread may be uncancelable. Attempts to cancel the thread are quietly ignored.
When initially created, a thread is synchronously cancelable.
4.2.1 Synchronous and Asynchronous Threads
An asynchronously cancelable thread may be canceled at any point in its execution.
A synchronously cancelable thread, in contrast, may be canceled only at particular places
in its execution.
These places are called cancellation points.The thread will queue a can-cellation request until it reaches the next cancellation point.|线程会将取消请求排队,直到到达下一个取消点再由程序处理。?????
To make a thread asynchronously cancelable, use pthread_setcanceltype.This
affects the thread that actually calls the function.The first argument should be
PTHREAD_CANCEL_ASYNCHRONOUS to make the thread asynchronously cancelable, or
PTHREAD_CANCEL_DEFERRED to return it to the synchronously cancelable state.
The second argument, if not null, is a pointer to a variable that will receive the previous can-cellation type for the thread.|则它指向的变量将保存线程的前一个取消类
型。?????
This call, for example, makes the calling thread
asynchronously cancelable.
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
What constitutes a cancellation point, and where should these be placed? The most
direct way to create a cancellation point is to call pthread_testcancel.This does
nothing except process a pending cancellation in a synchronously cancelable thread.
You should call pthread_testcancel periodically during lengthy computations in a
thread function, at points where the thread can be canceled without leaking any
resources or producing other ill effects.
取消点究竟是什么?它们应该被放置在哪里?最直接的创建一个取消点的方法是调用
pthread_testcancel。这个函数的唯一工作就是在一个可同步取消的线程中处理一个没有被处
理的线程取消请求。如果一个线程要执行长时间的计算过程,则应该定期在线程取消不会导
致资源泄露或产生其它负面影响的情况下调用pthread_testcancel。
Certain other functions are implicitly cancellation points as well.These are listed on
the pthread_cancelman page. Note that other functions may use these functions
internally and thus will indirectly be cancellation points.
4.2.2 Uncancelable Critical Sections
A thread may disable cancellation of itself altogether with the
pthread_setcancelstate function. Like pthread_setcanceltype, this affects the calling
thread.The first argument is PTHREAD_CANCEL_DISABLE to disable cancellation, or
PTHREAD_CANCEL_ENABLE to re-enable cancellation.The second argument, if not null,
points to a variable that will receive the previous cancellation state.This call, for
instance, disables thread cancellation in the calling thread.
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
Using pthread_setcancelstateenables you to implement critical sections. A critical sec-tion is a sequence of code that must be executed either in its entirety or not at all; in other words, if a thread begins executing the critical section, it must continue until the
end of the critical section without being canceled.
For example, suppose that you’re writing a routine for a banking program that
transfers money from one account to another.To do this, you must add value to the
balance in one account and deduct the same value from the balance of another
account. If the thread running your routine happened to be canceled at just the wrong
time between these two operations, the program would have spuriously increased the
bank’s total deposits by failing to complete the transaction.To prevent this possibility,
place the two operations in a critical section. //临界区设置不可取消
You might implement the transfer with a function such as process_transaction,
shown in Listing 4.6.This function disables thread cancellation to start a critical sec-tion before it modifies either account balance.
Listing 4.6 (critical-section.c) Protect a Bank Transaction with a Critical Section
#include <pthread.h>
#include <stdio.h>
#include <string.h>
/* An array of balances in accounts, indexed by account number. */
float* account_balances;
/* Transfer DOLLARS from account FROM_ACCT to account TO_ACCT. Return
0 if the transaction succeeded, or 1 if the balance FROM_ACCT is
too small. */
int process_transaction (int from_acct, int to_acct, float dollars)
{
int old_cancel_state;
/* Check the balance in FROM_ACCT. */
if (account_balances[from_acct] < dollars)
return 1;
continues
/* Begin critical section. */
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cancel_state);
/* Move the money. */
account_balances[to_acct] += dollars;
account_balances[from_acct] -= dollars;
/* End critical section. */
pthread_setcancelstate (old_cancel_state, NULL);
return 0;
}
Note that it’s important to restore the old cancel state at the end of the critical section
rather than setting it unconditionally to PTHREAD_CANCEL_ENABLE.This enables you to
call the process_transactionfunction safely from within another critical section—in
that case, your function will leave the cancel state the same way it found it.
注意在退出临界区的时候应恢复线程取消状态到进入临界区之前的状态,而不是无条件
地将线程取消状态设置为PTHREAD_CANCEL_ENABLE。这样可以使从一个临界区中调
用process_transaction的情况安全不出错——在这种情况下,这个函数会将线程取消状态恢
复到调用之前的状态。
4.2.3 When to Use Thread Cancellation
In general, it’s a good idea not to use thread cancellation to end the execution of a
thread, except in unusual circumstances. During normal operation, a better strategy is
to indicate to the thread that it should exit, and then to wait for the thread to exit on
its own in an orderly fashion.We’ll discuss techniques for communicating with the
thread later in this chapter, and in Chapter 5,“Interprocess Communication.”