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;
}
相关推荐
朱嘉鼎19 分钟前
C语言之可变参函数
c语言·开发语言
北冥湖畔的燕雀3 小时前
C++泛型编程(函数模板以及类模板)
开发语言·c++
QX_hao5 小时前
【Go】--map和struct数据类型
开发语言·后端·golang
你好,我叫C小白5 小时前
C语言 循环结构(1)
c语言·开发语言·算法·while·do...while
Evand J6 小时前
【MATLAB例程】基于USBL和DVL的线性回归误差补偿,对USBL和DVL导航数据进行相互补偿,提高定位精度,附代码下载链接
开发语言·matlab·线性回归·水下定位·usbl·dvl
爱喝白开水a7 小时前
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板_langchain prompt
开发语言·数据库·人工智能·python·langchain·prompt·知识图谱
Neverfadeaway8 小时前
【C语言】深入理解函数指针数组应用(4)
c语言·开发语言·算法·回调函数·转移表·c语言实现计算器
武子康8 小时前
Java-152 深入浅出 MongoDB 索引详解 从 MongoDB B-树 到 MySQL B+树 索引机制、数据结构与应用场景的全面对比分析
java·开发语言·数据库·sql·mongodb·性能优化·nosql
杰克尼8 小时前
JavaWeb_p165部门管理
java·开发语言·前端
一成码农8 小时前
JavaSE面向对象(下)
java·开发语言