Linux创建多个子线程并回收

本文介绍了C++中使用pthread创建子线程时参数传递和退出状态获取的方法。通过示例代码展示了如何将整型变量转换为void*类型传递,并在子线程中使用reinterpret_cast恢复。解释了为何不直接传递int地址的原因,以及为何在func函数中将void*转换为long类型以避免精度丢失。同时,详细说明了pthread_join函数如何获取并转换子线程的退出状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建子线程的逻辑相比子进程要更容易理解一些,因为线程没有像进程那样复制很多东西另起炉灶,子线程从传入的开始函数开始运行,但是难点在于传入参数和回收时获取退出状态,因为这两个原本都是void *类型的,而我们在使用时就必须进行转换。先上代码,然后再根据代码进行解释:

void pthread_check(int ret, const std::string msg = "error", int default_ret = 0);

using std::cout;
using std::endl;
namespace {
    pthread_mutex_t mutex1;
}

void *func(void * argc) {
//    int idx = *reinterpret_cast<int *>(argc);
    int idx = reinterpret_cast<long>(argc);
    pthread_mutex_lock(&mutex1);
    cout << "I am thread " << idx << "\n";
    pthread_mutex_unlock(&mutex1);
    //pthread_exit(argc);
    return argc;
}

void create_multi_thread() {
    pthread_mutex_init(&mutex1, nullptr);
    constexpr int N = 5;
    pthread_t tid[N];
    void *ret;
    for (int i = 0; i < N; ++i) {
        pthread_check(pthread_create(&tid[i], nullptr, func, reinterpret_cast<void *>(i)));
    }
    pthread_mutex_lock(&mutex1);
    cout << "I am thread 5" << "\n";
    pthread_mutex_unlock(&mutex1);
    for (int i = 0; i < N; ++i) {
        pthread_join(tid[i], &ret);
        pthread_mutex_lock(&mutex1);
        cout << "thread " << i << " exits with status : " << reinterpret_cast<long>(ret) << "\n";
        pthread_mutex_unlock(&mutex1);
    }
    pthread_exit(0);
}
	

其中pthread_check函数是我写的一个用于检查返回值的工具函数,mutex1是互斥量用于加锁控制输出(否则可能会很乱),子线程的工作很简单,就是输出自己是第几个线程。

  • 其中比较关键的地方就是pthread_create的第四个参数:向开始函数传参。这里我们可以看到把循环变量i转换使用reinterpret_cast转换成了void *类型的,然后再在开始函数func中使用reinterpret_cast函数将void *类型转换成了long类型。

    你可能觉得奇怪,为什么要把一个int类型直接转换成void *类型,为什么不将其地址传入呢?首先,要想清楚为什么使用void *类型作为传入参数的类型:我认为指针类型比基本类型更加广泛,指针类型可以保存基本类型的值,也可以指向内存,但是基本类型是无法指向内存的值的,因此使用空指针类型灵活度更高,这里仅仅是这个场景下需要传入一个整数而我们不想大费周章在堆上分配内存罢了,如果分配内存的话显然是需要指针的。

    可不可以传入int值的地址而不是将其本身传入进去呢?如果是单个线程应该是没有什么问题,但是多个子线程下就有问题了:因为该函数的栈空间是线程共享的,因此当主控线程修改了循环变量的值以后子线程中的值也会被修改,这显然不是我们想要的,如果还是感觉到无法理解的话可以自己手动尝试一下。

  • 第二个问题就是为什么要在func函数中使用reinterpret_castvoid *转换为long类型而不是int类型,因为在C++里面转换成int类型会报错说精度丢失(虽然C语言里面好像不会,我看大家都在随便转,感觉这个转换太魔性了,还是C++规范一些),但是一般情况下long类型和指针类型的大小是差不多大的,转换成 long类型就不用担心精度丢失了。

  • 第三个问题就是在使用pthread_join函数回收子线程的时候我们使用ret来获取子线程退出状态,经过测试发现在子线程的开始函数的返回值就是最后的子线程退出状态(当然我们也可以使用pthread_exit函数)

  • ret本身是void *类型,pthread_join函数需要一个void **类型,用来接收返回的void *类型,在接收成功后我们再次将其转换成long类型。

运行结果如下:
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值