void *threadCancel(void *arg) { int i = 0; printf("This is a new thread!\n"); for(i = 0; i < 5; i++) { printf("new thread running! i = %d\n", i); sleep(1); }
This is main thread,ret=0,tid=140496116229696 This is a new thread! new thread running! i = 0 main thread running!i = 0 new thread running! i = 1 main thread running!i = 1 cancel thread! ---------------- new thread running! i = 2 段错误 (核心已转储)
This is main thread,ret=0,tid=140382870578752 This is a new thread! new thread running! i = 0 main thread running!i = 0 new thread running! i = 1 main thread running!i = 1 cancel thread! ---------------- new thread running! i = 2 new thread running! i = 3 new thread running! i = 4 new thread exit! thread ret=new thread return
This is main thread,ret=0,tid=139966405953088 This is a new thread! main thread running!i = 0 new thread running!i = 0 main thread running!i = 1 cancel thread! ---------------- new thread running!i = 1 new thread running!i = 2 new thread running!i = 3 new thread running!i = 4 段错误 (核心已转储)
This is main thread,ret=0,tid=140574419174976 This is a new thread! main thread running!i = 0 new thread running!i = 0 main thread running!i = 1 cancel thread! ---------------- new thread running!i = 1 段错误 (核心已转储)
This is main thread,ret=0,tid=140581044491840 This is a thread test! main thread!i=0 main thread!i=1 ---------------- cancel thread! ---------------- thread test end, code=-1
关于取消点函数,我们在 Linux 下可以使用 man 7 pthreads 进行查看,取消点函数主要是帮助手册的 Cancellation points 部分。下边仅仅是罗列写这篇笔记时, Ubuntu21.04 中 man 手册上显示的取消点函数,只是便于自己查看,最好还是直接查 man 手册吧( POSIX.1-2001 and/or POSIX.1-2008 )。
在 POSIX.1-2001 and/or POSIX.1-2008 中必须是取消点的函数
点击查看函数列表
accept()
getpmsg()
open()
putmsg()
sem_wait()
system()
aio_suspend()
lockf()
openat()
putpmsg()
send()
tcdrain()
clock_nanosleep()
mq_receive()
pause()
pwrite()
sendmsg()
usleep()
close()
mq_send()
poll()
read()
sendto()
wait()
connect()
mq_timedreceive()
pread()
readv()
sigpause()
waitid()
creat()
mq_timedsend()
pselect()
recv()
sigsuspend()
waitpid()
fcntl()
msgrcv()
pthread_cond_timedwait()
recvfrom()
sigtimedwait()
write()
fdatasync()
msgsnd()
pthread_cond_wait()
recvmsg()
sigwait()
writev()
fsync()
msync()
pthread_join()
select()
sigwaitinfo()
getmsg()
nanosleep()
pthread_testcancel()
sem_timedwait()
sleep()
【说明】
(1)以下函数有备注,上边为了不占篇幅,将备注删去了
1 2 3 4 5
fcntl() F_SETLKW lockf() F_LOCK openat() [Added in POSIX.1-2008] sigpause() [POSIX.1-2001 only(moves to "may"list in POSIX.1-2008)] usleep() [POSIX.1-2001 only(function removed in POSIX.1-2008)]
This is main thread,ret=0,tid=139932233295424 This is a thread test! new pthread!i=0 main thread!i=0 new pthread!i=1 new pthread!i=2 main thread!i=1 ---------------- cancel thread! ---------------- new pthread!i=3 new pthread!i=4 I'm printf() Cancellation points! thread test end, code=-1
这说明取消点函数是执行完毕后退出的。
3.4 添加取消点
假设线程执行的是一个不含取消点的循环(譬如 for 循环、 while 循环),那么这时线程永远也不会响应取消请求,也就意味着除了线程自己主动退出,其它线程将无法通过向它发送取消请求而终止它,,但实际需求是,该线程必须可以被其它线程通过发送取消请求的方式终止,那这个时候怎么办?此时可以使用 pthread_testcancel() ,该函数目的很简单,就是产生一个取消点,线程如果已有处于挂起状态的取消请求,那么只要调用该函数,线程就会随之终止。
3.4.1 pthread_testcancel()
3.4.1.1 函数说明
在 linux 下可以使用 man pthread_testcancel 命令查看该函数的帮助手册。
1 2 3
/* Compile and link with -pthread. */ #include<pthread.h> voidpthread_testcancel(void);
This is main thread,ret=0,tid=140083039794752 This is a thread test! main thread!i=0 new thread!i=0 main thread!i=1 ---------------- cancel thread! ---------------- new thread!i=1 new thread!i=2 new thread!i=3 new thread!i=4 new thread!i=5 new thread!i=6 thread test end, code=-1
This is main thread,ret=0,tid=140136216446528 This is a thread test! new thread!i=0 main thread!i=0 main thread!i=1 ---------------- cancel thread! ---------------- new thread!i=1 new thread!i=2 new thread!i=3 new thread!i=4 new thread!i=5 new thread!i=6 new thread!i=7 new thread!i=8
/* Remove a cleanup handler installed by the matching pthread_cleanup_push. If EXECUTE is non-zero, the handler function is called. */ # define pthread_cleanup_pop(execute) \ __clframe.__do_it = (execute); \ } while (0)
intmain(int argc, char *argv[]) { int ret; pthread_t tid; void *retv; /* 1. 创建一个线程 */ ret = pthread_create(&tid, NULL, threadCleanUp, NULL); printf("This is main thread,ret=%d,tid=%lu\n", ret, tid); sleep(1); /* 2. 回收线程,若取消成功,这里将会返回错误,然后打印信息 */ ret = pthread_join(tid, &retv); if(ret != 0) printf("pthread_join error: %s\n", strerror(ret)); printf("thread test end, code=%ld\n", (long)retv); return0; }
void *threadCleanUp(void *arg) { int i = 0; pthread_cleanup_push(threadCleanUp1,"threadCleanUp1 runing!"); pthread_cleanup_push(threadCleanUp2,"threadCleanUp2 runing!"); printf("This is a new thread!\n"); for(i = 0; i < 5; i++) { printf("thread runing[%d]!\n", i); sleep(1); }printf("The new thread is ready to exit!\n"); pthread_exit("thread return"); pthread_cleanup_pop(0); pthread_cleanup_pop(0); return (void *)0; }
This is main thread,ret=0,tid=140032863184448 This is a new thread! thread runing[0]! thread runing[1]! thread runing[2]! thread runing[3]! thread runing[4]! The new thread is ready to exit! threadCleanUp2,arg=threadCleanUp2 runing! threadCleanUp1,arg=threadCleanUp1 runing! thread test end, code=93830143500505
This is main thread,ret=0,tid=139866019890752 main thread!i=0 This is a thread test! thread runing[0]! main thread!i=1 thread runing[1]! ---------------- cancel thread! ---------------- thread runing[2]! threadCleanUp2,arg=threadCleanUp2 runing! threadCleanUp1,arg=threadCleanUp1 runing! thread test end, code=-1
This is main thread,ret=0,tid=140153667556928 This is a thread test! thread runing[0]! thread runing[1]! thread runing[2]! thread runing[3]! thread runing[4]! threadCleanUp1,arg=threadCleanUp1 runing! thread test end, code=0