最近想写一篇std::future的文章,先来总结下,线程的退出值,以及如何回收这个退出值。
这里主要参看了网上的文章,具体链接见文尾。
在Linux中,线程的应用还是比较广泛的,同时,线程退出的返回值对线程来说,也是一种比较客观的数据传输。
本文主要是在Linux中进行测试,不涉及windows等其他OS。
1. 线程的创建
pthread_create(pthread_t *thread,const pthread_attr_t *attr,void*(*start_routine)(void*),void* arg);
首先,参数一:代表的是线程的pid地址
参数二:代表的是是否设置线程的分离属性,这里设置为NULL,不分离
参数三:代表的是线程的处理函数
参数四:线程处理函数的参数列表,这里设置为NULL,不带参数内容
(注意,这里主要是创建线程的作用)
2. 线程的等待
pthread_join(pthread_t thread, void **retval)
首先: 参数一: 代表线程pid
参数二: 代表线程的返回值 (--> 这个是本文讨论的重点参数)
3. 例子设计:
这里设计两个线程,线程一是通过一般的return返回,作为线程的返回值;线程二,则是使用线程库中的pthread_exit()函数
来进行返回参数。
首先,函数pthread_exit(void *retval)
这里的retval就是线程退出的时候返回给主线程的值,也是今天需要讨论的情况。
例子如下:
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define PTHREAD_NUM 2
void *sendData(void *arg)
{
static int count = 2;
pthread_exit((void*)(&count));
}
void *recvData(void *arg)
{
static int count = 3;
return (void *)(&count);
}
int main(int argc,char *argv[])
{
pthread_t pid[PTHREAD_NUM];
int retPid;
int *ret;
int *dat;
if((retPid = pthread_create(&pid[0],NULL,sendData,NULL)) != 0)
{
perror("create pid first failed");
return -1;
}
if((retPid = pthread_create(&pid[1],NULL,recvData,NULL)) != 0)
{
perror("create pid second failed");
return -1;
}
if(pid[0] != 0)
{
pthread_join(pid[0],(void**)&ret);
printf("get thread 0 message: %d\n",*ret);
}
if(pid[1] != 0)
{
pthread_join(pid[1],(void**)&dat);
printf("get thread 1 message: %d\n",*dat);
}
return 0;
}
讲解:这里的最主要的问题就是我们需要进行强制类型的转换。
首先,对于pthread_exit这个函数,他的返回参数的类型为void *,现在我们返回的是一个“整数”,因此必须将其进行转换
1. 先转换为整形指针,count为int类型,那么&count为int*类型,同样为了保持匹配,这里本人使用显式的调用,直接写作为
&count,其实这个表明了现在变成了一个int的指针,这个时候与void*匹配的话,需要进行强制转换,也就是代码中的
(void*)(&count);
2. return这个关键字进行返回值得时候,同样也是需要进行强制类型的转换。线程函数的返回类型是void*,那么对于count这个
整形数值来说,必须进行转换为void的指针类型(即void*),因此有:(void*)((int*)&count);
3. 对于接收返回值的线程函数pthread_join来说,有两个作用。其一就是等待线程结束,其二就是获取线程结束的时候返回的数值
是什么。所以,对于它的参数类型是void**这种二级指针的,我们可以把它分解为一级指针,这样就比较容易进行理解和调用。本文
讨论的是整数,那么设置接收返回值得为一个整形指针,这样就感觉给二级指针void**降阶了。
4. 对接收返回值得参数进行强制转换,这里定义接收返回值得类型是int*,因此转化为void**,也就是(void**)&ret,因为&ret就已
经说明了现在的类型为int**,然后显式地转为void**即可
5. 另外,本文在返回整数数值的时候使用到了static这个关键字,这是因为必须确定返回值的地址是不变的。对于count变量而言,在
内存上来讲,属于在栈区开辟的变量,那么在调用结束的时候,必然是释放内存空间的,相对而言,这时候,就没办法找到count所代表
内容的地址空间。这就是为什么很多人在看到swap交换函数的时候,为什么写成swap(int,int)是没有办法进行交换的,所以,如果我
们需要修改传过来的参数的话,必须是要使用这个参数的地址,或者是一个变量本身是不变的内存地址空间,这样才可以进行修改,否则,
修改失败或者返回值是随机值。
结果:
上述的结果表明,返回的数值是我们所要求的数值,是正确的。读者可以试着返回的是一个字符串,这样就比返回是一个整数
更加简单明了。说到底,整篇文章也就是强制转换的结果。读者可以更加深入地自己去理解