函数可以有返回值,那么线程作为一个handler是如何返回值的呢?在C语言中线程可以直接返回值,然后通过thread.join(返回值)来获取,但是C++不支持这样做,C++中是怎么返回线程的返回值的呢?本文将会比较详细的介绍C语言线程的返回值,以及几种C++线程替代返回值的方法。
个人简介:一个全栈工程师的升级之路!
个人专栏:C/C++精进之路
CSDN主页 发狂的小花
人生秘诀:学习的本质就是极致重复!
目录
1 C语言线程
1.1 pthread
1.2 C语言线程
1.2.1 步骤
1.2.2 pthread_create参数说明
1.2.3 pthread_join参数说明
1.3 C语言线程返回值
2 C++线程
2.1 thread
2.2 C++线程调用参数种类
2.2.1 函数指针
2.2.2 Lambda表达式
2.2.3 成员函数
2.2.4 函数对象
2.3 C++线程返回值
2.3.1 共享指针
2.3.2 future和promise配合实现
在C语言中,可以使用POSIX线程库(pthread)来实现多线程编程。使用pthread库可以创建、同步和销毁线程。头文件是
(1)包含头文件 #include
(2)申请线程对象,pthread_t thread1;
(3)创建线程 pthread_create(&thread1,NULL,handler,&in);
参数说明:
第一个参数:thread1为线程对象地址
第二个参数:线程属性,pthread 线程属性包括:
(1)调度策略,
(2)调度的优先级,
(3)线程的分离状态(分离线程:主动结束 和 可汇合线程:等待原有创建线程结束 才结束,即pthread_ioin()调用后,该子线程结束),
(4)线程ID
(5) 线程的继承性
第三个参数:线程handler处理函数
一般定义为 void * handler(void *data){}; 如果需要返回值,可以申请堆空间返回
pthread_join(thread_id,void * (ret)); void *ret是返回值的地址,可以用来得到返回
值的地址
第四个参数:
线程处理函数的输入参数,用来传参给处理函数
pthread_join(argv1,argv2);
参数说明:
argv1 为线程对象
argv2 这里传入的二维指针,指的是存储返回值地址的指针的地址
以下是一个简单的示例代码:
#include
#include
#include
void *print_hello(void *arg) {
printf("Hello from thread %ld\n", (long)arg);
return NULL;
}
int main() {
pthread_t thread1, thread2;
int rc1, rc2;
long t1 = 1, t2 = 2;
/* Create independent threads each of which will execute function */
rc1 = pthread_create(&thread1, NULL, print_hello, (void *)t1);
if (rc1) {
fprintf(stderr, "Error: Unable to create thread %d", rc1);
exit(-1);
}
rc2 = pthread_create(&thread2, NULL, print_hello, (void *)t2);
if (rc2) {
fprintf(stderr, "Error: Unable to create thread %d", rc2);
exit(-1);
}
/* Wait till threads are complete before main continues. */
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
运行结果:
如下实现了线程返回值:
#include
#include
#include
void * add1_handler(void *arg)
{
int *ret = (int*)malloc(sizeof(int));
*ret = *((int*)arg) + 1;
return ret;
}
int main() {
pthread_t thread1;
int in = 34;
int rc1 = 0;
/* Create independent threads each of which will execute function */
rc1 = pthread_create(&thread1, NULL, add1_handler, (void*)&in);
if (rc1) {
fprintf(stderr, "Error: Unable to create thread %d", rc1);
exit(-1);
}
/* Wait till threads are complete before main continues. */
int *ret_value = NULL;
pthread_join(thread1, (void**)(&ret_value));
printf("最终的结果: %d \n",*ret_value);
free(ret_value);
return 0;
}
运行结果:
最终的结果: 35
C++线程是一种轻量级的执行单元,可以在单个程序中并发执行多个任务。C++标准库提供了对线程的支持,包括创建、同步和销毁线程等功能。
在C++中,可以使用
头文件中的函数来创建和管理线程。以下是一个简单的示例代码:
#include
#include
void print_hello() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
// 创建一个新线程并执行print_hello函数
std::thread t(print_hello);
// 等待线程执行完成
t.join();
return 0;
}
运行结果:
可以将函数指针作为参数传递给std::thread
类来定义线程。
#include
#include
void print_hello() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
std::thread t(&print_hello); // 使用函数指针定义线程
t.join();
return 0;
}
运行结果:
可以使用Lambda表达式来定义线程。
#include
#include
int main() {
std::thread t([]{
std::cout << "Hello from thread!" << std::endl;
}); // 使用Lambda表达式定义线程
t.join();
return 0;
}
运行结果:
可以将成员函数作为参数传递给std::thread
类来定义线程。
#include
#include
class MyClass {
public:
void print_hello() {
std::cout << "Hello from thread!" << std::endl;
}
};
int main() {
MyClass obj;
std::thread t(&MyClass::print_hello, &obj); // 使用成员函数定义线程
t.join();
return 0;
}
运行结果:
上述代码使用成员函数作为线程的handler,并把实例传入,以达到调用某一对象的成员函数。
可以将函数对象作为参数传递给std::thread
类来定义线程。函数对象需要重载operator()
运算符。
#include
#include
class MyFunctor {
public:
void operator()() {
std::cout << "Hello from thread!" << std::endl;
}
};
int main() {
MyFunctor functor;
std::thread t(functor); // 使用函数对象定义线程
t.join();
return 0;
}
运行结果:
上述代码通过运算符()重载实现用函数对象完成线程的参数。
由于C++线程的join不支持接收参数,因此不可以通过这种方式返回值,只能通过传入共享指针或者对象,以及使用future和promise来实现线程返回值。
本质上传递变量、对象等都是共享指针。
#include
#include
using namespace std;
void * add1_handler(void *arg)
{
*(int*)arg = 56;
}
int main() {
int value = 11;
std::cout << "执行前value: " << value << std::endl;
std::thread t(&add1_handler,&value);
// 等待线程执行完成
t.join();
std::cout << "执行后value: " << value << std::endl;
return 0;
}
运行结果:
执行前value: 11
执行后value: 56
std::future和std::promise是封装好的两个类模板,这两个类需要配合使用,他们的头文件是#include
std::future,它表示存储着一个未来会被初始化的变量。这个变量可以通过std::future提供的成员函数std::future::get()来得到。如果在这个变量被赋值之前就有别的线程试图通过std::future::get()获取这个变量,那么这个线程将会被阻塞到这个变量可以获取为止。
std::promise同样也是一个类模板,这个对象承诺在未来一定会初始化一个变量(这个变量也就是std::future中的变量)。
每一个std::promise对象都有一个与之关联的std::future对象。当std::promise设置值的时候,这个值就会赋给std::future中的对象了。
#include
#include
#include
void func2(int x, int y,std::promise &promiseObj) {
promiseObj.set_value(x+y);
}
int main()
{
//计算(a+b)/(x+y)
//用三个线程,一个线程计算a+b,另一个线程计算x+y
int a, b, x, y;
a = 10, b = 8, x = 2, y = 4;
int sum1, sum2;
//声明一个类
std::promise promiseObj;
//将future和promise关联
std::future futureObj = promiseObj.get_future();
//模板传参的时候使用ref,否则传参失败
std::thread t1(func2, a, b, ref(promiseObj));
t1.join();
//获取值
sum1 = futureObj.get();
std::cout << "sum1=" << sum1 << std::endl;
//不能直接复用上面的future和promise
std::promise promiseObj2;
std::future futureObj2 = promiseObj2.get_future();
std::thread t2(func2, x, y, ref(promiseObj2));
t2.join();
sum2 = futureObj2.get();
std::cout << "sum2=" << sum2 << std::endl;
std::cout << "sum1/sum2=" << sum1 / sum2 << std::endl;
return 0;
}
运行结果:
sum1=18
sum2=6
sum1/sum2=3
分析结果可知,上述代码实现了线程返回值,通过将一个promise对象绑定到一个future上,通过传入promise对象作为线程的返回值,最终由future获取promise的值,本质上也是一种共享指针的方式。
我的分享也就到此结束啦
如果我的分享也能对你有帮助,那就太好了!
若有不足,还请大家多多指正,我们一起学习交流!
未来的富豪们:点赞→收藏⭐→关注
感谢大家的观看和支持!最后,☺祝愿大家每天有钱赚!!!