111.连接已终止的线程、线程分离、线程取消

一、连接已终止的线程

功能:和一个已经终止的线程进行连接

回收子线程的资源

这个函数是阻塞函数,调用一次只能回收一个子线程

参数:thread:需要回收的子线程的ID

retval: 接收子线程推出时的返回值

返回值:0 成功

非0 失败,返回错误号

代码示例:

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

void *callback(void *arg)
{
    printf("child pthread id:%ld\n", (long)pthread_self());
    sleep(3);
    return NULL;
}

int main()
{
    pthread_t tid;

    int ret = pthread_create(&tid, NULL, callback, NULL);

    if (ret != 0)
    {
        char *errstr = strerror(ret);
        printf("error: %s\n", errstr);
        return 1;
    }

    // 主线程
    for (int i = 0; i < 5; i++)
    {
        printf("%d\n", i);
    }

    printf("tid:%ld, main thread id:%ld\n", (long)tid, (long)pthread_self());

    //主线程调用pthread_join回收子线程的资源
    ret=pthread_join(tid, NULL);

    if (ret != 0)
    {
        char *errstr = strerror(ret);
        printf("error: %s\n", errstr);
        return 1;
    }

    printf("回收子线程资源成功!\n");

    // 等待子线程结束
    pthread_exit(NULL);

    return 0;
}

这里将在child id打印之后,睡眠3s才会打印回收子线程资源成功

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

//int value=10;//全局变量
void *callback(void *arg)
{
    printf("child pthread id:%ld\n", (long)pthread_self());
    // sleep(3);
    // return NULL;
    int value = 10;//局部变量
    pthread_exit((void *)&value);
}

int main()
{
    pthread_t tid;

    int ret = pthread_create(&tid, NULL, callback, NULL);

    if (ret != 0)
    {
        char *errstr = strerror(ret);
        printf("error: %s\n", errstr);
        return 1;
    }

    // 主线程
    for (int i = 0; i < 5; i++)
    {
        printf("%d\n", i);
    }

    printf("tid:%ld, main thread id:%ld\n", (long)tid, (long)pthread_self());

    // 主线程调用pthread_join回收子线程的资源
    int *pthread_retval;
    ret = pthread_join(tid, (void **)&pthread_retval);

    if (ret != 0)
    {
        char *errstr = strerror(ret);
        printf("error: %s\n", errstr);
        return 1;
    }

    printf("xeti data:%d\n", *pthread_retval);

    printf("回收子线程资源成功!\n");

    // 等待子线程结束
    pthread_exit(NULL);

    return 0;
}

二、线程分离

pthread_detach 是 POSIX 线程库中的一个函数,用于将线程标记为"分离状态",以表明当线程退出时,其资源可以被系统自动回收,而不需要等待其他线程调用 pthread_join 来获取线程的退出状态。

以下是 pthread_detach 的基本语法:

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

int pthread_detach(pthread_t thread);
  • thread:要标记为分离状态的线程的线程标识符。

调用 pthread_detach 函数后,指定的线程就会变成"分离状态"的线程。这意味着当该线程退出时,它的资源(包括线程控制块等)会被自动回收,而不会形成僵尸线程。分离状态的线程不再需要其他线程调用 pthread_join 来进行清理。

代码示例:

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

void *callback(void *arg)
{
    printf("child pthread id:%ld\n", (long)pthread_self());
    return NULL;
}

int main()
{
    pthread_t tid;

    int ret = pthread_create(&tid, NULL, callback, NULL);

    if (ret != 0)
    {
        char *errstr = strerror(ret);
        printf("error1: %s\n", errstr);
        return 1;
    }

    printf("tid:%ld, main thread id:%ld\n", tid, pthread_self());

    // 设置子线程分离,子线程分离后,子线程结束时对应的资源就不需要主线程释放
    ret = pthread_detach(tid);

    if (ret != 0)
    {
        char *errstr = strerror(ret);
        printf("error2: %s\n", errstr);
        return 1;
    }

    ret = pthread_join(tid, NULL);

    if (ret != 0)
    {
        char *errstr = strerror(ret);
        printf("error3: %s\n", errstr);
        return 1;
    }

    // 等待子线程结束
    pthread_exit(NULL);

    return 0;
}

此时已经子线程分离了,在调用pthread_join就会报错

三、线程取消

pthread_cancel 是 POSIX 线程库中的一个函数,用于请求取消另一个线程的执行。这个函数的使用需要非常小心,因为线程可能正在执行一些关键的任务,而取消可能引起资源泄漏或不一致性的问题。

以下是 pthread_cancel 的基本语法:

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

int pthread_cancel(pthread_t thread);
  • thread:要取消的线程的线程标识符。

调用 pthread_cancel 函数将发送一个取消请求给指定的线程。实际上,它并不会立即终止线程的执行,而是等待线程到达取消点(cancellation point)。取消点是一些由线程库定义的特定位置,线程在这些位置上检查是否有取消请求。如果线程在取消点上,它会执行相应的取消动作。如果线程没有到达取消点,取消请求会在线程到达下一个取消点时生效。

要使一个线程支持取消请求,可以使用以下两个函数:

pthread_setcancelstate:

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

int pthread_setcancelstate(int state, int *oldstate);
  • state:用于设置取消状态的值,可以是 PTHREAD_CANCEL_ENABLE(启用取消)或 PTHREAD_CANCEL_DISABLE(禁用取消)。
  • oldstate:用于存储原始取消状态的变量的地址。如果不关心原始状态,可以将其设置为 NULL

pthread_setcanceltype:

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

int pthread_setcanceltype(int type, int *oldtype);
  • type:用于设置取消类型的值,可以是 PTHREAD_CANCEL_DEFERRED(延迟取消)或 PTHREAD_CANCEL_ASYNCHRONOUS(异步取消)。
  • oldtype:用于存储原始取消类型的变量的地址。如果不关心原始类型,可以将其设置为 NULL

代码示例:

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

void *thread_function(void *arg) {
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);

    while (1) {
        printf("线程正在执行\n");
        sleep(1);
    }

    pthread_exit(NULL);
}

int main() {
    pthread_t thread_id;

    // 创建一个线程
    pthread_create(&thread_id, NULL, thread_function, NULL);

    // 等待一段时间
    sleep(3);

    // 发送取消请求
    pthread_cancel(thread_id);

    // 等待线程结束
    pthread_join(thread_id, NULL);

    printf("主线程结束\n");

    return 0;
}
相关推荐
浪子明X5 小时前
十六位账本怎样发现传输差错:Internet Checksum 生活类比
开发语言
Flynt6 小时前
Java 27 升级实测:默认值动得比新特性多,有个老参数会让 JVM 直接起不来
java·jvm·后端
xiangyun618 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法
xiangyun618 小时前
【408数据结构 06】双链表、循环链表、静态链表
c语言·开发语言·数据结构·c++·算法
白远山9 小时前
家政服务家政社区派单实战:调度系统架构设计与实现指南
java·开发语言·小程序·架构·需求分析
DevRay10 小时前
Java 21虚拟线程深度实战:告别线程池焦虑,百万并发吞吐量直接翻倍(原理+代码+避坑)
java·开发语言
用户0942485680310 小时前
第10章:OpenJDK异常体系、栈轨迹与错误诊断入门
java·jvm
free-elcmacom10 小时前
C++学习<1>程序分区
开发语言·c++
醉颜凉10 小时前
Java 必看:如何彻底避免 HashMap 多线程死循环问题?
java·开发语言
默 语11 小时前
Java新手入门:从零开始安装JDK并配置环境变量
java·开发语言·python·mysql·group by·1024程序员节·数据去重