创建子线程的逻辑相比子进程要更容易理解一些,因为线程没有像进程那样复制很多东西另起炉灶,子线程从传入的开始函数开始运行,但是难点在于传入参数和回收时获取退出状态,因为这两个原本都是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_cast
将void *
转换为long
类型而不是int
类型,因为在C++里面转换成int
类型会报错说精度丢失(虽然C语言里面好像不会,我看大家都在随便转,感觉这个转换太魔性了,还是C++规范一些),但是一般情况下long
类型和指针类型的大小是差不多大的,转换成long
类型就不用担心精度丢失了。 -
第三个问题就是在使用
pthread_join
函数回收子线程的时候我们使用ret
来获取子线程退出状态,经过测试发现在子线程的开始函数的返回值就是最后的子线程退出状态(当然我们也可以使用pthread_exit
函数) -
ret
本身是void *
类型,pthread_join
函数需要一个void **
类型,用来接收返回的void *
类型,在接收成功后我们再次将其转换成long
类型。
运行结果如下: