pthread_cancel(pthread_t pd);
用于取消一个函数,它通常需要被取消线程的配合
默认情况(延迟取消),它就是给pd设置取消标志, pd线程在很多时候会查看自己是否有取消请求
如果有就主动退出, 这些查看是否有取消的地方称为取消点
如果是异步取消(pthread_setcanceltype设置),那么 pthread_cancel同时还给发送信号通知对方
对方理解会结束自己
pthread_cancel (pd):
设置pd的请求标志
如果是异步模式,发送信号
pd收到信号后退出(线程如何退出参考
pthread_create )
取消点的本质就是修改取消模式为异步模式,并检查是否有未决取消请求
- int
-
attribute_hidden
-
__pthread_enable_asynccancel (void)
-
{//
-
struct pthread *self = THREAD_SELF;
-
int oldval = THREAD_GETMEM (self, cancelhandling);
-
-
while (1)
-
{
-
int newval = oldval | CANCELTYPE_BITMASK;
- 已经是异步模式,无须任何检查,因为异步模式中线程只要收到请求,就会退出
-
if (newval == oldval)
-
break;
-
-
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 ();
-
}
-
-
break;
-
}
-
-
/* Prepare the next round. */
-
oldval = curval;
-
}
-
-
return oldval;
-
}
如果原来是异步取消类型,那么pthread_cancel将直接导致它被取消,所以根本不需要主动检查
(CANCELTYPE_BIT标示异步), 否则设置并检查
很多地方都是包含取消点,包括
pthread_join()、
pthread_testcancel()、pthread_cond_wait()、
pthread_cond_timedwait()、sem_wait()、sigwait()
write,read,大多数会阻塞的系统调用
pthread_join:
/* Switch to asynchronous cancellation. */
int oldtype = CANCEL_ASYNC ();
等待线程结束
/* Restore cancellation mode. */
CANCEL_RESET (oldtype);
write等的实现在
./nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h 中
本质就是
old = enable async type
syscall
restore old type
xcm@u32:~/test/pthread$ cat write.c
int main()
{
write(1, "\n", 1);
}
xcm@u32:~/test/pthread$ gcc write.c -static
xcm@u32:~/test/pthread$ objdump -d >tmp
- 0804f8a0 <__libc_write>:
- %gs:0xc检查是否多线程,单线程没有必要
-
804f8a0: 65 83 3d 0c 00 00 00 cmpl $0x0,%gs:0xc
-
804f8a7: 00
-
804f8a8: 75 21 jne 804f8cb <__write_nocancel+0x21>
-
-
0804f8aa <__write_nocancel>:
-
804f8aa: 53 push %ebx
-
804f8ab: 8b 54 24 10 mov 0x10(%esp),%edx
-
804f8af: 8b 4c 24 0c mov 0xc(%esp),%ecx
-
804f8b3: 8b 5c 24 08 mov 0x8(%esp),%ebx
-
804f8b7: b8 04 00 00 00 mov $0x4,%eax
-
804f8bc: cd 80 int $0x80
-
804f8be: 5b pop %ebx
-
804f8bf: 3d 01 f0 ff ff cmp $0xfffff001,%eax
-
804f8c4: 0f 83 36 20 00 00 jae 8051900 <__syscall_error>
-
804f8ca: c3 ret
-
804f8cb: e8 30 0e 00 00 call 8050700 <__libc_enable_asynccancel>
默认情况下,只要有取消请求,并且遇到取消点就会退出
所以如果一个线程不到达取消点, 比如仅仅操作一些数据结构就没有被中断的风险
否则容易死锁
- #include <pthread.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <sys/wait.h>
-
-
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
void unlock(void *unused)
-
{
-
pthread_mutex_unlock(&lock);
-
}
-
-
void *threadfunc(void *parm)
-
{
-
while (1)
-
{
-
//pthread_cleanup_push(unlock, 0);
-
pthread_mutex_lock(&lock);
-
write(111, "\n", 1);
-
pthread_mutex_unlock(&lock);
-
//pthread_cleanup_pop(0);
-
}
-
return 0;
-
}
-
-
int main(int argc, char **argv)
-
{
-
pthread_t thread;
-
while (1)
-
{
-
pthread_create(&thread, NULL, threadfunc, NULL);
-
pthread_cancel(thread);
-
pthread_join(thread, 0);
-
-
printf("locking ..\n");
-
pthread_mutex_lock(&lock);
-
printf("done\n");
-
pthread_mutex_unlock(&lock);
-
}
-
return 0;
-
}
把注释去掉就OK了,它在退出之前会先执行其cleanup函数
阅读(14050) | 评论(0) | 转发(0) |