女主宣言
由于工作需求,笔者最近在阅读 Pulsar C++ 客户端的实现,发现该客户端虽然是基于 C++11 编写的,但却自己编写了 Future 和 Promise 类,随着阅读的深入,也体会到了在这里”重复造轮子“的原因。本文将根据lib/Future.h中的源码,讲述C++中Future和Promise的一种简单实现~
PS:丰富的一线技术、多元化的表现形式,尽在“360云计算”,点关注哦!
1
前言
众所周知,C++11 提供了对并发编程的支持。首先提供了对不同平台的线程设施的简单包装 thread,并提供了 native_handle() 方法可以得到平台相关的线程句柄,从而调用底层线程相关的函数。另外,C++11 还提供了 future 和 promise 来支持基于任务的程序设计。
1
C++11的并发API
首先回顾下 C++11 的并发设施。
std::thread
如果熟悉 pthread 库的话,那么 C++11 的 std::thread 会非常容易上手,它使用了可变模板参数这一技术,使得编写线程函数不必麻烦地进行 void* 和 T* 的相互转换。
举个例子,要在线程中将两个 int 求和然后转换成十六进制字符串,得到结果。
使用 pthread 的代码:
#include <pthread.h>
#include <iostream>
#include <string>
using namespace std;
struct Package {
int x, y; // input
std::string result; // output
void calculate() { result = std::to_string(x + y); }
};
int main(int argc, char* argv[]) {
pthread_t tid;
Package package{1, 3, ""};
pthread_create(
&tid, nullptr,
[](void* param) -> void* { // 线程函数必须是 void* (void*)
static_cast<Package*>(param)->calculate();
return nullptr;
},
&package); // 传入 void* 作为输入参数
pthread_join(tid, nullptr); // 第二个参数是 void**,如果非空的话可以得到线程函数返回的 void*
cout << "result: " << package.result << endl;
return 0;
}
为了简化代码,这里忽略 pthread API 的返回值检查,以及 param 是否为空的检查。可见,pthread 需要对参数打包成一个结构体。
再看看 std::thread 的等价实现:
#include <string>
#include <thread>
using namespace std;
int main(int argc, char* argv[]) {
string result;
thread t([](int x, int y,
string& s) { s = to_string(x + y); }, // 函数签名是 T (Args...)
1, 3, ref(result));
t.join();
cout << "result: " << result << endl;
return 0;
}
最大的改进是线程函数签名从底层的 void*(void*) 变成了返回任意类型、接收任意数量和类型的参数的 T(Args&&...)。注意传入引用时需要用 std::ref 将引用转换成可拷贝的某种结构。
如何得到返回值
问题来了,其实上面的实现并不直观,毕竟将计算结果作为返回值,比将计算结果的引用作为输入参数要更符合直观。
std::thread 直接就无法得到返回值。反而 pthread 线程函数可以返回的那个 void* 保存返回结果,比如:
#include <pthread.h>
#include <iostream>
#include <string>
using namespace std;
struct Input {
int x, y;
std::string sum() const { return to_string(x + y); }
};
int main(int argc, char* argv[]) {
Input input{1, 3};
pthread_t tid;
pthread_create(
&tid, nullptr,
[](void* param) -> void* {
return new std::string(static_cast