文章首发于我的个人博客:欢迎大佬们来逛逛
文章目录
- 处理带返回值的函数
- async
- packaged_task
- promise
处理带返回值的函数
有三种方法:
- async
- packaged_task
- promise
async
第一种方法是使用 async 函数。
步骤:
- 使用
async
创建线程处理函数 - 使用
.get()
获取返回值。
async函数具有两个属性
- launch::async(默认):表示创建线程处理函数并且立刻执行
- launch::defered:延期,当使用wait或者get的时候才会执行线程处理函数
async函数的返回值:std::future
类型,通过调用其 get 方法获取返回值
下面分别演示了普通函数与类的成员函数以及 defered 的作用:
int value1(int num) {return num;
}//类对象
class Foo {
public:Foo() {}int getValue(int num) {std::chrono::milliseconds duration(2000);std::this_thread::sleep_for(duration);return num * 2;}
};void testAsync() {//直接执行,默认是launch::asyncstd::future<int> res1 = std::async(value1, 100);std::cout << res1.get() << '\n';Foo m{};//类成员函数std::future<int> res2 = std::async(&Foo::getValue, &m, 200);std::cout << res2.get() << '\n';//不会立刻执行auto res3 = std::async(std::launch::deferred, &Foo::getValue, m, 400);//调用get,执行线程std::cout << res3.get() << '\n';
}
packaged_task
第二种方法是使用 packaged_task 方法
步骤:
- 使用
packaged_task
来包装线程处理函数 - 然后将这个包装好的函数加入到线程
thread
中,并且执行线程处理函数 - 最后使用这个 packaged_task 调用
get_future
来获取 future,然后调用get
获取值。
package_task 函数包装语法:
//包装普通函数
std::packaged_task<返回类型(形参列表)> pack1(函数名称);//包装类的成员函数
std::packaged_task<返回类型(形参列表)> pack2(bind(函数地址,成员变量地址,placeholders占位符))//包装lambda表达式
std::packaged_task<int(int)> pack3([](形参列表){xxxxreturn xxx;
});
可以看到对于类的成员函数是相对比较复杂的。
void testPackaged_task() {//1. 普通函数的包装std::packaged_task<int(int)> pack1(value1);std::thread t1(std::ref(pack1),100); //转换为&&t1.join();std::cout << pack1.get_future().get() << '\n';//2. 类中成员函数的包装Foo m{};std::packaged_task<int(int)> pack2(std::bind(&Foo::getValue, &m, std::placeholders::_1));std::thread t2(std::ref(pack2), 200);t2.join();std::cout << pack2.get_future().get() << '\n';//3. lambda表达式std::packaged_task<int(int)> pack3([](int num) {std::cout << "id: " << std::this_thread::get_id() << '\n';return num * 2;});std::thread t3(std::ref(pack3),300);t3.join();std::cout << pack3.get_future().get() << '\n';
}
promise
第三种方法是使用 promise 类型
步骤:
- 传递
promise
类型的变量到线程处理函数中。 - 我们正常执行线程处理函数即可,无需使用return语句,在操作完成后把需要的值
set_value
设置为promise 的值。 - 然后使用
thread
创建并且执行线程处理函数。 - 然后我们就可以在外部使用 .
get_future
获取 future对象, 继而 .get
获取值。
这种方法的特点:
- 无需显示设置 return 语句
- 需要往线程处理函数添加一个额外的 promise 类型的参数。
例如这个是我们的线程处理函数,我们需要返回 num *3
, 但是现在我们添加一个promise 类型的参数(注意是引用),然后直接 set_value
即可,然后再外部就可以直接访问这个值了。
void testThread(std::promise<int>& pms, int num) {std::cout << get_id() << '\n';pms.set_value(num * 3);
}
- 返回线程处理函数的值:
std::promise<int> pms;
std::thread t1(testThread, std::ref(pms), 100);
t1.join();
auto num = pms.get_future().get();
std::cout << num << '\n';
这种方法也可以传递线程的值到另一个线程处理函数中:
有一个 testGetValueThread
线程函数,我们需要把刚才获取的 num*3 的值再传递进去,则可以在这个线程函数内调用 .get_future().get()
来传递参数。
下面是两种方法,这里使用了函数重载作为线程处理函数,需要使用static_cast来避免重载歧义。
通过static_cast消除重载函数的歧义
void testGetValueThread(std::promise<int>& pms) {std::cout << "获取值: " << pms.get_future().get() << '\n';
}
void testGetValueThread(int num) {std::cout << "获取值: " << num << '\n';
}...std::promise<int> pms2;pms2.set_value(99);//值传递到其他线程中//通过static_cast消除重载函数的歧义std::thread t2(static_cast<void(*)(std::promise<int>&)>(testGetValueThread), std::ref(pms2));t2.join();std::thread t3(static_cast<void(*)(int)>(testGetValueThread), num);t3.join();