线程的取消学习笔记

目录

取消线程-pthread_cancel:

线程清理:


取消线程-pthread_cancel:

cpp 复制代码
int pthread_cancel(pthread_t thread);//杀死一个线程

示例代码:

cpp 复制代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *func(void *arg)
{
    printf("This is child thread\n");
    while (1)
    {
        sleep(5); //取消点
    }
    pthread_exit("thread return");
}
int main()
{
    void *retv;
    pthread_t tid;
    int i;   
    pthread_create(&tid,NULL,func,NULL);
    sleep(5);
    pthread_cancel(tid);
    pthread_join(tid,&retv);
    printf("thread ret=%s\n",(char *)retv);
    while (1)
    {
        sleep(1);
    }
}

线程取消,必须要设置取消点,如果没有则手动设置。不是说取消就取消,线程的取消点主要是阻塞的系统调用。

运行结果:

出现段错误的问题:

出错原因,retv接收不到字符串,所以不能打印。将printf那一行注释掉就可以。

手动设置取消点代码示例如下:

cpp 复制代码
void *func(void *arg)
{
    printf("This is child thread\n");
    while (1)
    {
        //sleep(5);
        pthread_testcancel();
    }
    pthread_exit("thread return");
}

设置取消使能或禁止

cpp 复制代码
int pthread_setcancelstate(int state, int *oldstate);

示例代码:

cpp 复制代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *func(void *arg)
{
    printf("This is child thread\n");
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//前5秒不能取消
    //while (1)
    {
        sleep(5);
        pthread_testcancel();
    }
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//后5秒可以取消
    while (1)
    {
        sleep(1);
    }
    pthread_exit("thread return");
}
int main()
{
    void *retv;
    pthread_t tid;
    int i;   
    pthread_create(&tid,NULL,func,NULL);
    sleep(5);//不能呢个没有sleep,因为可能线程还没禁止取消就已经取消了
    pthread_cancel(tid);
    pthread_join(tid,&retv);
    //printf("thread ret=%s\n",(char *)retv);
    while (1)
    {
        sleep(1);
    }
}

设置取消类型

cpp 复制代码
int pthread_setcanceltype(int type,int *oldtype);

PTHREAD_CANCEL_DEFERRED //等到取消点才取消(默认是这个)

PTHREAD_CANCEL_ASYNCHRONOUS //目标线程会立即取消

线程清理:

必要性: 当线程非正常终止,需要清理一些资源

cpp 复制代码
void pthread_cleanup_push(void (*routine)(void *),void *arg)
void pthread_cleanup_pop(int execute)

routine函数被执行的条件:

  1. 被pthread_cancel取消掉
  2. 执行pthread_exit
  3. 非0参数执行pthread_cleanup_pop()

示例代码:

cpp 复制代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void cleanup1(void *arg)
{
    printf("cleanup1, arg=%s\n",(char *)arg);
}
void cleanup2(void *arg)
{
    printf("cleanup2, arg=%s\n",(char *)arg);
}
void *func(void *arg)
{
    printf("This is child thread\n");
    pthread_cleanup_push(cleanup1, "abcd");
    pthread_cleanup_push(cleanup2, "efgh");
    //while (1)
    {
        sleep(1);
    }
    // pthread_exit("thread return");
    // pthread_cleanup_pop(0);//必须和前面成对出现
    // pthread_cleanup_pop(0);

    //等效于这种写法
    pthread_cleanup_pop(1);//必须和前面成对出现
    pthread_cleanup_pop(1);
    pthread_exit("thread return");
}
int main()
{ 
    void *retv;
    pthread_t tid;
    int i;   
    pthread_create(&tid,NULL,func,NULL);
    sleep(1);//不能呢个没有sleep,因为可能线程还没禁止取消就已经取消了
    pthread_cancel(tid);
    pthread_join(tid,&retv);
    printf("thread return = %s\n",(char *)retv);
    while(1)
    {
        sleep(1);
    }
}

运行结果:

注意:

  1. 必须成对使用,即时pthread_cleanup_pop不会被执行到也必须写上,否则编译错误。
  2. pthread_cleanup_pop()被执行且参数为0,pthread_cleanup_push回调函数routine不会被执行。
  3. pthread_cleanup_push和pthread_cleanup_pop可以写多对,routine执行顺序正好相反
  4. 线程内return可以结束线程,也可以给pthread_join返回值,但不能触发pthread_cleanup_push里面的回调函数,所以我们结束线程尽量使用pthread_exit退出线程
相关推荐
不绝19116 小时前
C#进阶——内存
开发语言·c#
风送雨16 小时前
Go 语言进阶学习:第 1 周 —— 并发编程深度掌握
开发语言·学习·golang
num_killer16 小时前
小白的Docker学习
学习·docker·eureka
小北方城市网16 小时前
第 5 课:服务网格(Istio)实战|大规模微服务的流量与安全治理体系
大数据·开发语言·人工智能·python·安全·微服务·istio
jghhh0116 小时前
自适应信号时频处理方法MATLAB实现(适用于非线性非平稳信号)
开发语言·算法·matlab
AC赳赳老秦16 小时前
Go语言微服务文档自动化生成:基于DeepSeek的智能解析实践
大数据·开发语言·人工智能·微服务·golang·自动化·deepseek
古城小栈16 小时前
Rust 之 迭代器
开发语言·rust
r***123816 小时前
GO 快速升级Go版本
开发语言·redis·golang
黎雁·泠崖16 小时前
二叉树入门全攻略:从树的概念到遍历实现
c语言·数据结构
木木木一16 小时前
Rust学习记录--C5 Rust struct
开发语言·学习·rust