(八)QT专题-多线程编程-POSIX主动结束和被动结束线程
Page420
1,线程主动结束
线程主动结束,一般就在线程函数中使用return语句或调用pthread_exit()函数。函数pthread_exit()的原型声明如下:
void pthread_exit(void *retval)
其中,参数retval是线程退出时返回给主线程的值,线程函数的返回类型是 void *。值得注意的是,在main线程中调用pthread_exit(NULL);
的时候将结束main线程,但进程并不会立即退出。
#include "MainWindow.h"
#include <QApplication>
#include <unistd.h> //for sleep
#include <iostream>
#include <pthread.h>
using namespace std;
#define handle_error_en(en,msg) do {errno = en;perror(msg);exit(EXIT_FAILURE);}while (0);
#define PTHREAD_NUM 2
void *thrfunc1(void *arg)
{
static int count = 1;
pthread_exit((void*)(&count)); //方式一:pthread_exit() 结束线程
}
void *thrfunc2(void *arg)
{
static int count = 2;
return (void*)(&count); //方式二:return 结束线程
}
int main(int argc, char *argv[])
{
// QApplication a(argc, argv);
// MainWindow w;
// w.show();
pthread_t pid[PTHREAD_NUM];
int retPid;
int *pRet1;
int *pRet2;
if((retPid = pthread_create(&pid[0],NULL,thrfunc1,NULL)) != 0)
{
perror("create pid first failed");
return -1;
}
if((retPid = pthread_create(&pid[1],NULL,thrfunc2,NULL)) != 0)
{
perror("create pid second failed");
return -1;
}
if(pid[0] != 0)
{
pthread_join(pid[0],(void**)&pRet1);
printf("get thread 0 exitcode: %d\n",*pRet1);
}
if(pid[1] != 0)
{
pthread_join(pid[1],(void**)&pRet2);
printf("get thread 1 exitcode: %d\n",*pRet2);
}
pthread_exit(NULL); // the main thread will exit, but main process will not
cout<<"main thread has exited,this line will not run\n"<<endl;
// return a.exec();
}
Output:
get thread 0 exitcode: 1
get thread 1 exitcode: 2
2,线程被动结束
某个线程可能在执行一项耗时的计算任务,而用户没有耐心,希望结束该线程,此时线程要被动地结束。如何被动结束呢?
一种方法是在同进程的另外一个线程中通过函数pthread_kill()发送信号给要结束的线程,目标线程收到信号后退出;另外一种方法是在同进程的其他线程中通过函数pthread_cancel()来取消目标线程的执行。
定时取消任务:
#include "MainWindow.h"
#include <QApplication>
#include <unistd.h> //for sleep
#include <iostream>
#include <signal.h>
#include <pthread.h>
using namespace std;
#define handle_error_en(en,msg) do {errno = en;perror(msg);exit(EXIT_FAILURE);}while (0);
#define PTHREAD_NUM 2
static void on_signal_term(int sig)
{
cout<<"sub thread will exit"<<endl;
pthread_exit(NULL);
}
void *thrfunc(void *arg)
{
//接收信号的线程必须先用sigaction函数注册该信号的处理函数。
signal(SIGQUIT,on_signal_term);
int tm = 50;
while(true)
{
cout<<"thrfunc--left:"<<tm<<"s--"<<endl;
sleep(1);
tm--;
}
return(void*)0;
}
int main(int argc, char *argv[])
{
// QApplication a(argc, argv);
// MainWindow w;
// w.show();
pthread_t pid;
int res;
res = pthread_create(&pid,NULL,thrfunc,NULL);
sleep(5);
pthread_kill(pid,SIGQUIT);
pthread_join(pid,NULL);
cout<<"sub thread has completed,main thread will exit\n";
pthread_exit(NULL); // the main thread will exit, but main process will not
cout<<"main thread has exited,this line will not run\n"<<endl;
// return a.exec();
}
Output:
thrfunc--left:50s--
thrfunc--left:49s--
thrfunc--left:48s--
thrfunc--left:47s--
thrfunc--left:46s--
sub thread will exit
sub thread has completed,main thread will exit
在执行子线程的时候,主线程等了5秒后开始向子进程发送信号SIGQUIT。在子线程中已经注册了SIGQUIT的处理函数on_signal_term()。如果没有注册信号SIGQUIT的处理函数,则将调用默认的处理程序来结束线程所属的进程。
pthread_kill(pid,0)
可以根据返回值判断线程当前状态(不存在,无效,存在)。
除了通过函数pthread_kill()发送信号来通知线程结束,我们还可以通过函数pthread_cancel()来取消某个线程的运行。
int pthread_cancel(pthread_t thread);
其中,参数thread表示要被取消线程(目标线程)的线程ID。
在死循环中可以加入pthread_testcancel()
来让系统测试取消请求。
另外常见的取消点有printf、pthread_testcancel、read/write、sleep等函数调用的地方。