(八)QT专题-多线程编程-POSIX主动结束和被动结束线程

2023-02-13  本文已影响0人  GoodTekken

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等函数调用的地方。

上一篇下一篇

猜你喜欢

热点阅读