如何正确的终止正在运行的子线程Word格式.docx
- 文档编号:13597562
- 上传时间:2022-10-12
- 格式:DOCX
- 页数:8
- 大小:18.81KB
如何正确的终止正在运行的子线程Word格式.docx
《如何正确的终止正在运行的子线程Word格式.docx》由会员分享,可在线阅读,更多相关《如何正确的终止正在运行的子线程Word格式.docx(8页珍藏版)》请在冰豆网上搜索。
pthread_exit
此函数的使用场景是当前运行的线程运行pthread_exit得到退出,对于各个子线程能够清楚地知道自己在什么时候结束的情景下,非常好用,可是实际上往往很多时候一个线程不能知道知道在什么时候该结束,例如遭遇Ctrl+C时,kill进程时,当然如果排除所有的外界干扰的话,那就让每个线程干完自己的事情后,然后自觉地乖乖的调用pthread_exit就可以了,这并不是本文需要讨论的内容,本文的情景就是讨论如何处理特殊情况。
这里还有一种方法,既然子线程可以通过pthread_exit来正确退出,那么我们可以在遭遇Ctrl+C时,kill进程时处理signal信号,然后分别给在某一个线程可以访问的公共区域存上一个flag变量,线程内部每运行一段时间(很短)来检查一下flag,若发现需要终止自己时,自己调用pthread_exit,此法有一个弱点就是当子线程需要进行阻塞的操作时,可能无暇顾及检查flag,例如socket阻塞操作。
如果你的子线程的任务基本没有非阻塞的函数,那么这么干也不失为一种很好的方案。
pthread_kill
不要被这个可怕的邪恶的名字所吓倒,其实pthread_kill并不像他的名字那样威力大,使用之后,你会感觉,他徒有虚名而已
pthread_kill的职责其实只是向指定的线程发送signal信号而已,并没有真正的kill掉一个线程,当然这里需要说明一下,有些信号的默认行为就是exit,那此时你使用pthread_kill发送信号给目标线程,目标线程会根据这个信号的默认行为进行操作,有可能是exit。
当然我们同时也可以更改获取某个信号的行为,以此来达到我们终止子线程的目的。
1#define_MULTI_THREADED
2#include&
lt;
pthread.h&
gt;
3#include&
stdio.h&
4#include&
signal.h&
5#include"
check.h"
6
7#defineNUMTHREADS3
8voidsighand(intsigno);
9
10void*threadfunc(void*parm)
11{
12pthread_tself=pthread_self();
13pthread_id_np_ttid;
14intrc;
15
16pthread_getunique_np(&
amp;
self,&
tid);
17printf("
Thread0x%.8x%.8xentered\n"
tid);
18errno=0;
19rc=sleep(30);
20if(rc!
=0&
&
errno==EINTR){
21printf("
Thread0x%.8x%.8xgotasignaldeliveredtoit\n"
22tid);
23returnNULL;
24}
25printf("
Thread0x%.8x%.8xdidnotgetexpectedresults!
rc=%d,errno=%d\n"
26tid,rc,errno);
27returnNULL;
28}
29
30intmain(intargc,char**argv)
31{
32intrc;
33inti;
34structsigactionactions;
35pthread_tthreads[NUMTHREADS];
36
37printf("
EnterTestcase-%s\n"
argv[0]);
38
39printf("
Setupthealarmhandlerfortheprocess\n"
);
40memset(&
actions,0,sizeof(actions));
41sigemptyset(&
actions.sa_mask);
42actions.sa_flags=0;
43actions.sa_handler=sighand;
44
45rc=sigaction(SIGALRM,&
actions,NULL);
46checkResults("
sigaction\n"
rc);
47
48for(i=0;
i&
NUMTHREADS;
++i){
49rc=pthread_create(&
threads[i],NULL,threadfunc,NULL);
50checkResults("
pthread_create()\n"
51}
52
53sleep(3);
54for(i=0;
55rc=pthread_kill(threads[i],SIGALRM);
56checkResults("
pthread_kill()\n"
57}
58
59for(i=0;
60rc=pthread_join(threads[i],NULL);
61checkResults("
pthread_join()\n"
62}
63printf("
Maincompleted\n"
64return0;
65}
66
67voidsighand(intsigno)
68{
69pthread_tself=pthread_self();
70pthread_id_np_ttid;
71
72pthread_getunique_np(&
73printf("
Thread0x%.8x%.8xinsignalhandler\n"
74tid);
75return;
76}
运行输出为:
1Output:
2
3EnterTestcase-QP0WTEST/TPKILL0
4Setupthealarmhandlerfortheprocess
5Thread0x000000000000000centered
6Thread0x000000000000000dentered
7Thread0x000000000000000eentered
8Thread0x000000000000000cinsignalhandler
9Thread0x000000000000000cgotasignaldeliveredtoit
10Thread0x000000000000000dinsignalhandler
11Thread0x000000000000000dgotasignaldeliveredtoit
12Thread0x000000000000000einsignalhandler
13Thread0x000000000000000egotasignaldeliveredtoit
14Maincompleted
我们可以通过截获的signal信号,来释放掉线程申请的资源,可是遗憾的是我们不能再signal处理里调用pthread_exit来终结掉线程,因为pthread_exit是中介当前线程,而signal被调用的方式可以理解为内核的回调,不是在同一个线程运行的,所以这里只能做处理释放资源的事情,线程内部只有判断有没有被中断(一般是EINTR)来断定是否要求自己结束,判定后可以调用pthread_exit退出。
此法对于一般的操作也是非常可行的,可是在有的情况下就不是一个比较好的方法了,比如我们有一些线程在处理网络IO事件,假设它是一种一个客户端对应一个服务器线程,阻塞从Socket中读消息的情况。
我们一般在网络IO的库里面回家上对EINTR信号的处理,例如recv时发现返回值小于0,检查error后,会进行他对应的操作。
有可能他会再recv一次,那就相当于我的线程根本就不回终止,因为网络IO的类有可能不知道在获取EINTR时要终止线程。
也就是说这不是一个特别好的可移植方案,如果你线程里的操作使用了很多外来的不太熟悉的类,而且你并不是他对EINTR的处理手段是什么,这是你在使用这样的方法来终止就有可能出问题了。
而且如果你不是特别熟悉这方面的话你会很苦恼,“为什么我的测试代码全是ok的,一加入你们部门开发的框架进来就不ok了,肯定是你们框架出问题了”。
好了,为了不必要的麻烦,我最后没有使用这个方案。
pthread_cancel
这个方案是我最终采用的方案,我认为是解决这个问题,通用的最好的解决方案,虽然前面其他方案的有些问题他可能也不好解决,但是相比较而言,还是相当不错的
pthread_cancel可以单独使用,因为在很多系统函数里面本身就有很多的断点,当调用这些系统函数时就会命中其内部的断点来结束线程,如下面的代码中,即便注释掉我们自己设置的断点pthread_testcancel()程序还是一样的会被成功的cancel掉,因为printf函数内部有取消点(如果大家想了解更多的函数的取消点情况,可以阅读《Unix
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 如何 正确 终止 正在 运行 线程