如何正确的终止正在运行的子线程

您所在的位置:网站首页 怎样结束一个线程的程序 如何正确的终止正在运行的子线程

如何正确的终止正在运行的子线程

2024-05-11 06:00| 来源: 网络整理| 查看: 265

  最近开发一些东西,线程数非常之多,当用户输入Ctrl+C的情形下,默认的信号处理会把程序退出,这时有可能会有很多线程的资源没有得到很好的释放,造成了内存泄露等等诸如此类的问题,本文就是围绕着这么一个使用场景讨论如何正确的终止正在运行的子线程。其实本文更确切的说是解决如何从待终止线程外部安全的终止正在运行的线程

首先我们来看一下,让当前正在运行的子线程停止的所有方法

1.任何一个线程调用exit

2.pthread_exit

3.pthread_kill

4.pthread_cancel 

 

下面我们一一分析各种终止正在运行的程序的方法

 

任何一个线程调用exit

任何一个线程只要调用了exit都会导致进程结束,各种子线程当然也能很好的结束了,可是这种退出会有一个资源释放的问题.我们知道当一个进程终止时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在终止时内核也会自动关闭它打开的所有文件。没错,标准C++ IO流也会很好的在exit退出时得到flush并且释放资源,这些东西并不会造成资源的浪费(系统调用main函数入口类似于exit(main(argc,argv))).表面上似乎所有的问题都能随着进程的结束来得到很好的处理,其实并不然,我们程序从堆上分配的内存就不能得到很好的释放,如new ,delete后的存储空间,这些空间进程结束并不会帮你把这部分内存归还给内存.(本文初稿时,因基础不牢固,此处写错,事实上无论进程这样结束,系统都将会释放掉所有代码所申请的资源,无论是堆上的还是栈上的。(感谢ZKey的指导)。这种结束所有线程(包括主线程)的方式实际上在很多时候是非常可取的,但是对于针对关闭时进行一些别的逻辑的处理(指非资源释放逻辑)就不会很好,例如我想在程序被kill掉之前统计一下完成了多少的工作,这个统计类似于MapReduce,需要去每个线程获取,并且最后归并程一个统一的结果等等场景)

 

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   3 #include   4 #include   5 #include "check.h"  6   7 #define NUMTHREADS 3  8 void sighand(int signo);  9  10 void *threadfunc(void *parm) 11 { 12   pthread_t             self = pthread_self(); 13   pthread_id_np_t       tid; 14   int                   rc; 15  16   pthread_getunique_np(&self, &tid); 17   printf("Thread 0x%.8x %.8x entered\n", tid); 18   errno = 0; 19   rc = sleep(30); 20   if (rc != 0 && errno == EINTR) { 21     printf("Thread 0x%.8x %.8x got a signal delivered to it\n", 22            tid); 23     return NULL; 24   } 25   printf("Thread 0x%.8x %.8x did not get expected results! rc=%d, errno=%d\n", 26          tid, rc, errno); 27   return NULL; 28 } 29  30 int main(int argc, char **argv) 31 { 32   int                     rc; 33   int                     i; 34   struct sigaction        actions; 35   pthread_t               threads[NUMTHREADS]; 36  37   printf("Enter Testcase - %s\n", argv[0]); 38   39   printf("Set up the alarm handler for the process\n"); 40   memset(&actions, 0, sizeof(actions)); 41   sigemptyset(&actions.sa_mask); 42   actions.sa_flags = 0; 43   actions.sa_handler = sighand; 44  45   rc = sigaction(SIGALRM,&actions,NULL); 46   checkResults("sigaction\n", rc); 47  48   for(i=0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3