1.Pthreads支持3种取消模式,分别为:off(关),deferred(推迟),asynchronous(异步).模式是两位二进制编码,分别是“取消状态”和“取消类型”,每种模式实际上包含开和关两种状态。
模式 状态 类型 含义
off 禁用 两者之一 取消Pending被推迟直到启用取消模式
deferred 启用 推迟 在下一个取消点执行取消
asynchronous 启用 异步 可以随时执行取消
默认情况下,取消被推迟执行,并且仅仅能在程序中特定的点被执行,该点检查线程是否被要求终止,被称为取消点。
可能等待一个无界时间的大多数函数应该称为被推迟取消点,推迟的取消点包括等待条件变量,读写文件,以及线程可能被阻塞一段可观的时间的其它函数。
pthread_testcancel的特殊函数,该函数仅仅是一个推迟的取消点,如果线程没被要求终止,它很快会返回,这允许你将任何函数转变为取消点。
The pthread_testcancel() function shall create a cancellation point in the calling thread. The pthread_testcancel() function shall have no effect if
cancelability is disabled.
如果线程有一个异步取消类型集,或当线程下次到达一个被推迟的取消点时,取消请求将被系统释放。当发生这种情况,系统将设置线程的取消类型是PTHREAD_CANCEL_DELIVEROD,取消状态为PTHREAD_CANCEL_DISABLE。即,线程能清理并终止自己,而不必担心再次被取消。
当作为一个取消点的函数检测到一个未解决的取消请求时,函数将不返回调用者。如果有任何活跃的清除函数,就调用它们,线程终止。没有办法在处理取消并继续执行----线程必须被终止,或者被彻底推迟取消。
如果线程取消的"取消状态"被关闭的话,这个时候请求取消一个线程,则线程记得它被取消但不会采取任何动作,直到“取消状态”被重新启用,因为启用“取消状态”操作不是一个取消点,如果希望未被解决的取消请求能够被立刻处理,需要测试未解决的取消请求(pthread_testcancel).
关于pthread_textcancel的实例:
#include "errors.h"
int count;
void *thread_routine(void *arg)
{
int type;
DPRINTF(("thread_routine starting\n"));
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &type);
for(count = 0; ; count++){
if(count % 1000 == 0){
DPRINTF(("calling testcancel\n"));
pthread_testcancel();
}
}
}
int main(int argc, char **argv)
{
int status = 0;
pthread_t thread_id;
void *result = NULL;
pthread_setconcurrency(2);
status = pthread_create(&thread_id, NULL, thread_routine, NULL);
if(status != 0){
err_abort(status, "create thread_routine");
}
sleep(2);
DPRINTF(("calling cancel\n"));
status = pthread_cancel(thread_id);
if(status != 0){
err_abort(status, "cancel thread_id");
}
DPRINTF(("calling join\n"));
status = pthread_join(thread_id, &result);
if(status != 0){
err_abort(status, "join thread_id");
}
if(result == PTHREAD_CANCELED){
printf("thread canceled at iteration %d\n", count);
}
else{
printf("thread was not canceled\n");
}
exit(0);
}
|
关于线程取消默认的“取消状态”和“取消模型”,测试代码实例:
#include "../errors.h"
void *thread_routine(void *arg)
{
int state, type;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &type);
if(state == PTHREAD_CANCEL_ENABLE){
printf("Default cancelability state is PTHREAD_CANCEL_ENABLE\n");
}
if(type == PTHREAD_CANCEL_DEFERRED){
printf("Default cancelability type is PTHREAD_CANCEL_DEFERRED\n");
}
pthread_setcancelstate(state, &state);
pthread_setcanceltype(type, &type);
}
int main(int argc, char **argv)
{
int status = 0;
pthread_t thread_id;
status = pthread_create(&thread_id, NULL, thread_routine, NULL);
if(status != 0){
err_abort(status, "create thread");
}
status = pthread_join(thread_id, NULL);
if(status != 0){
err_abort(status, "join thread");
}
exit(0);
}
运行结果:
[xxxx@localhost chap5]$ ./a.out Default cancelability state is PTHREAD_CANCEL_ENABLE Default cancelability type is PTHREAD_CANCEL_DEFERRED
|
2.推迟取消:(PTHREAD_CANCEL_ENABLE && PTHREAD_CANCEL_DEFERRED)
线程仅仅到达取消点时才能响应取消请求。
大多数取消点包含可以“无限”时间阻塞线程的I/O操作,它们是可取消的,以便等待能够被打断。
一个例子:
#include "../errors.h"
int count;
void *thread_routine(void *arg)
{
int state, status;
for(count = 0; ; count++){
if((count % 126) == 0){
status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
if(status != 0){
err_abort(status, "cancel disabled");
}
sleep(1);
status = pthread_setcancelstate(state, &state);
if(status != 0){
err_abort(status, "cancel enable");
}
}
else if((count % 1000) == 0){
pthread_testcancel();
}
}
}
int main(int argc, char **argv)
{
pthread_t thread_id;
int status = 0;
void *result = NULL;
pthread_setconcurrency(2);
status = pthread_create(&thread_id, NULL, thread_routine, NULL);
if(status != 0){
err_abort(status, "create thread");
}
status = pthread_cancel(thread_id);
if(status != 0){
err_abort(status, "cancel thread_id");
}
status = pthread_join(thread_id, &result);
if(status != 0){
err_abort(status, "join thread_id");
}
if(result == PTHREAD_CANCELED){
printf("Thread canceled at iteration %d\n", count);
}
else{
printf("Thread was not canceled\n");
}
exit(0);
}
|
3.异步取消:(PTHREAD_CANCEL_ASYNCHRONOUS && PTHREEAD_CANCEL_ENABLE)
当异步取消被启用时,不允许调用任何能获得资源的函数,除非函数是“异步取消安全”的,否则当异步取消被启用时你不该调用任何函数。
有Pthreads规定的异步取消安全函数是pthread_cancel,pthread_setcancelstate,pthread_setcanceltype(并且当启用异步取消时,没有必要调用pthread_cancel)。
一个例子:
#include "../errors.h"
int a[10][10], b[10][10], c[10][10];
void *thread_routine(void *arg)
{
int i, j, k, status, type;
for(i = 0; i < 10; i++){
for(j = 0; j < 10; j++){
a[i][j] = i;
b[i][j] = j;
}
}
while(1){
status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &type);
if(status != 0){
err_abort(status, "set asyn");
}
for(i = 0; i < 10; i++){
for(j = 0; j < 10; j++){
c[i][j] = 0;
for(k = 0; k < 10; k++){
c[i][j] += a[i][k] * b[k][j];
}
}
}
status = pthread_setcanceltype(type, &type);
if(status != 0){
err_abort(status, "unset asyn");
}
for(i = 0; i < 10; i++){
for(j = 0; j < 10; j++){
a[i][j] = c[i][j];
}
}
}
}
int main(int argc, char **argv)
{
int status = 0;
pthread_t thread_id;
void *result = NULL;
pthread_setconcurrency(2);
status = pthread_create(&thread_id, NULL, thread_routine, NULL);
if(status != 0){
err_abort(status, "create thread_id");
}
sleep(1);
printf("after 1 second\n");
status = pthread_cancel(thread_id);
if(status != 0){
err_abort(status, "cancel thread_id");
}
status = pthread_join(thread_id, &result);
if(status != 0){
err_abort(status, "join thread_id");
}
if(result == PTHREAD_CANCELED){
printf("Thread was canceled\n");
}
else{
printf("Thread was not canceled\n");
}
exit(0);
}
|
4.清除:
当一段代码段被取消时,需要恢复一些状态,必须使用清除处理器。
当线程在鞥代一个条件变量时被取消,线程将被唤醒,并保持互斥量加锁状态,在线程终止前,需要恢复不变量,并且释放互斥量。
任何线程都可以push和pop清理处理程序:
void pthread_cleanup_push(void (*function)(void *), void *arg);
void pthread_cleanup_pop(int execute);
当:
调用线程被取消(某个线程调用pthread_cancel);
调用线程自愿终止(pthread_exit,或者从自己的线程起始函数返回)。
时调用清理处理程序。
清理处理程序可以恢复任何需要恢复的状态。
pthread_cleanup_pop总是删除调用线程的“取消清理栈”中位于栈顶的函数,且如果execute不为0,就调用该函数(就算线程没被取消,清理处理程序也会被调用)。
]#include "../errors.h"
#define THREADS 5
typedef struct control_tag{
int count, busy;
pthread_mutex_t mutex;
pthread_cond_t cond;
}control_t;
control_t control = {0, 1, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER};
void cleanup_routine(void *arg)
{
control_t *st = (control_t *)arg;
int status;
st->count--;
printf("cleanup_routine: count == %d\n", st->count);
status = pthread_mutex_unlock(&st->mutex);
if(status != 0){
err_abort(status, "unlock mutex");
}
}
void *thread_routine(void *arg)
{
int status;
pthread_cleanup_push(cleanup_routine, (void *)&control);
status = pthread_mutex_lock(&control.mutex);
if(status != 0){
err_abort(status, "thread lock mutex");
}
control.count++;
while(control.busy == 1){
status = pthread_cond_wait(&control.cond, &control.mutex);
if(status != 0){
err_abort(status, "thread wait cond");
}
}
pthread_cleanup_pop(1);
}
int main(int argc, char **argv)
{
pthread_t thread_id[THREADS];
int i, status;
void *result = NULL;
for(i = 0; i < THREADS; i++){
status = pthread_create(&thread_id[i], NULL, thread_routine, NULL);
if(status != 0){
err_abort(status, "create thread");
}
}
sleep(2);
for(i = 0; i < THREADS; i++){
status = pthread_cancel(thread_id[i]);
if(status != 0){
err_abort(status, "cancel thread");
}
status = pthread_join(thread_id[i], &result);
if(status != 0){
err_abort(status, "join thread");
}
if(result == PTHREAD_CANCELED){
printf("thread %d canceled\n", i);
}
else{
printf("thread %d was not canceled\n");
}
}
exit(0);
}
运行结果:
[xxxx@localhost chap5]$ ./a.out cleanup_routine: count == 4 thread 0 canceled cleanup_routine: count == 3 thread 1 canceled cleanup_routine: count == 2 thread 2 canceled cleanup_routine: count == 1 thread 3 canceled cleanup_routine: count == 0 thread 4 canceled
|
阅读(881) | 评论(0) | 转发(0) |