【Linux系统编程】31.pthread_detach、线程属性

发布于:2024-05-10 ⋅ 阅读:(28) ⋅ 点赞:(0)

目录

pthread_detach

参数pthread

返回值

测试代码1

测试结果

pthread_attr_init

参数attr

返回值

pthread_attr_destroy

参数attr

返回值

pthread_attr_setdetachstate

参数attr

参数detachstate

返回值

测试代码2

测试结果

线程使用注意事项

pthread_detach

       实现线程分离。线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。网络、多线程服务器常用。

man 3 pthread_detach

参数pthread

待分离的线程ID。

返回值

成功:0

失败:错误号

测试代码1

分离一个线程,并回收。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>

void *HuiDiao_HanShu(void *arg)
{
    printf("这是子线程的回调函数,子线程的进程ID是%d,子线程ID是%lu。\n", getpid(), pthread_self());
    return (void *)0;
}

int main(int argc, char *argv[])
{
    int flag;
    pthread_t ZiXianCheng_ID; //子线程ID
    void *num = NULL;

    flag = pthread_create(&ZiXianCheng_ID, NULL, HuiDiao_HanShu, NULL); //创建子线程
    if (flag != 0)
    {
        printf("创建子线程错误:%s\n", strerror(flag));
        exit(1);
    }

    printf("这是主线程,进程ID是%d,线程ID是%lu。\n", getpid(), pthread_self());

    printf("开始分离子线程!\n");
    flag = pthread_detach(ZiXianCheng_ID);
    if (flag != 0)
    {
        printf("分离子线程错误:%s\n", strerror(flag));
        exit(1);
    }
    printf("分离子线程完成!\n");

    printf("这是主线程,先睡一会,再回收子线程!\n");
    sleep(1);
    printf("这是主线程,睡醒了!\n");

    printf("开始回收子线程!\n");
    flag = pthread_join(ZiXianCheng_ID, &num);
    if (flag != 0)
    {
        printf("回收子线程错误:%s\n", strerror(flag));
        exit(1);
    }
    printf("回收子线程完成!\n");
    printf("num=%d\n", (int)num);

    pthread_exit(NULL);

    return 0;
}

测试结果

分离后的子线程结束后,会自动清理PCB,无需回收。

pthread_attr_init

初始化线程属性。

man 3 pthread_attr_init

参数attr

传出参数的属性。

返回值

成功:0

失败:错误号

pthread_attr_destroy

销毁线程属性所占用的资源。

man 3 pthread_attr_destroy

参数attr

传出参数的属性。

返回值

成功:0

失败:错误号

pthread_attr_setdetachstate

设置线程属性。

man 3 pthread_attr_setdetachstate

参数attr

已初始化的线程属性。

参数detachstate

分离线程:PTHREAD_CREATE_DETACHED

非分离线程:PTHREAD _CREATE_JOINABLE

返回值

成功:0

失败:错误号

测试代码2

设置线程的属性为分离属性,再回收子进程。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>

void *HuiDiao_HanShu(void *arg)
{
    printf("这是子线程的回调函数,子线程的进程ID是%d,子线程ID是%lu。\n", getpid(), pthread_self());
    return (void *)0;
}

int main(int argc, char *argv[])
{
    int flag;
    pthread_t ZiXianCheng_ID;         //子线程ID
    pthread_attr_t XianCheng_ShuXing; //线程属性
    void *num = NULL;

    flag = pthread_attr_init(&XianCheng_ShuXing); //初始化线程属性
    if (flag != 0)
    {
        printf("线程属性初始化错误:%s\n", strerror(flag));
        exit(1);
    }

    flag = pthread_attr_setdetachstate(&XianCheng_ShuXing, PTHREAD_CREATE_DETACHED); //设置线程属性为分离属性
    if (flag != 0)
    {
        printf("设置线程属性错误:%s\n", strerror(flag));
        exit(1);
    }

    flag = pthread_create(&ZiXianCheng_ID, &XianCheng_ShuXing, HuiDiao_HanShu, NULL); //创建子线程,借助线程属性将子进程分离
    if (flag != 0)
    {
        printf("创建子线程错误:%s\n", strerror(flag));
        exit(1);
    }

    flag = pthread_attr_destroy(&XianCheng_ShuXing); //销毁线程属性
    if (flag != 0)
    {
        printf("线程属性销毁错误:%s\n", strerror(flag));
        exit(1);
    }

    printf("这是主线程,进程ID是%d,线程ID是%lu。\n", getpid(), pthread_self());

    printf("这是主线程,先睡一会,再回收子线程!\n");
    sleep(1);
    printf("这是主线程,睡醒了!\n");

    printf("开始回收子线程!\n");
    flag = pthread_join(ZiXianCheng_ID, &num);
    if (flag != 0)
    {
        printf("回收子线程错误:%s\n", strerror(flag));
        exit(1);
    }
    printf("回收子线程完成!\n");
    printf("num=%d\n", (int)num);

    pthread_exit(NULL);

    return 0;
}

测试结果

说明子线程已被成功分离,无需回收。

线程使用注意事项

  1. 主线程退出其他线程不退出,主线程应调用 pthread_exit。

  2. 避免僵尸线程,被join线程可能在join函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程栈中的值。

  3. malloc和mmap申请的内存可以被其他线程释放。

  4. 应避免在多线程模型中调用fork除非马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中均 pthread_exit。

  5. 信号的复杂语义很难和多线程共存,应避免在多线程引入信号机制。


网站公告

今日签到

点亮在社区的每一天
去签到