本章目标:
主线程与次线程通信的问题
次线程与主线程通信的问题
案例清单:计算阶乘代码示例
#include<iostream> #include<string> #include<thread> #include<mutex> #include<fstream>
using namespace std;
void factorial(int N) { int res = 1; for (int i = N; i > 1; i--) { res *= i; } cout << "results" << res << endl; }
int main() { std::thread t1(factorial,4);
t1.join(); return 0; } |
但是,如果将子线程打印的结果res返回到主线程main中,根据前面的知识,则可能需要使用下面的方法
//……
void factorial(int N,int &x) {
int res = 1; for (int i = N; i > 1; i--) { res *= i; } cout << "results" << res << endl; x = res; }
int main() { int x; std::thread t1(factorial,4,std::ref(x));
t1.join(); return 0; }
|
但这样还不够,这是因为x被主线程和次线程同时共享,因此需要设置互斥,添加锁。由于x的传递,因此还要使用条件变量std::condition_variable cond;显然程序中还要加入wait(),unlock()从而使得程序变得复杂。
解决方式为使用std::future<>模板库。
代码清单:
#include<iostream> #include<string> #include<thread> #include<mutex> #include<fstream>
using namespace std;
int factorial(int N) {
int res = 1; for (int i = N; i > 1; i--) { res *= i; } cout << "results" << res << endl; return res; } #include<future> int main() { int x; std::future<int>fu = std::async(factorial,4); //std::thread t1(factorial,4,std::ref(x)); x = fu.get(); //t1.join(); return 0; } |
结果如下
果,因为 std::thread 并不提供直接接收返回值的机制。这里就需要 std::async 函数模板(也 是在头文件中声明的)了。
当任务的结果你不着急要时,你可以使用 std::async 启动一个异步任务。与 std::thread 对 象等待运行方式的不同, std::async 会返回一个 std::future 对象,这个对象持有最终计算 出来的结果。当你需要这个值时,你只需要调用这个对象的get()成员函数;并且直到"期望"状 态为就绪的情况下,线程才会阻塞;之后,返回计算结果。下面清单中代码就是一个简单的
例子。
关注如何传回计算的结果,因为 std::thread 并不提供直接接收返回值的机制。这里就需要 std::async 函数模板(也
是在头文件中声明的)了。
当任务的结果你不着急要时,你可以使用 std::async 启动一个异步任务。与 std::thread 对象等待运行方式的不同, std::async 会返回一个 std::future 对象,这个对象持有最终计算出来的结果。当你需要这个值时,你只需要调用这个对象的get()成员函数;并且直到"期望"状态为就绪的情况下,线程才会阻塞;之后,返回计算结果。
Std::async并不一定会创建一个新的线程,如果添加参数 std::launch::deferred后,即std::future<int > fu=std::async(std::launch::deferred,factorial,4);则不会启动新的线程,到了x=fu.get()时,会在原来的线程中调用factorial函数。而使用std::launch::async后则表示创建新的线程。由于这两种为"或"的关系,因此,可以像清单中的表示。
从子线程获取主线程中的变量
上面的是从主线程获得子线程中的变量,下面是从子线程获得主线程变量的方法。
使用promise类型的变量。代码清单如下:
#include<iostream> #include<string> #include<thread> #include<mutex> #include<fstream>
using namespace std;
int factorial(std::future<int>& f) {
int res = 1; int N = f.get(); for (int i = N; i > 1; i--) { res *= i; } cout << "results" << res << endl; return res; } #include<future> int main() { int x; std::promise<int> p; std::future<int> f = p.get_future();
std::future<int>fu = std::async(factorial,std::ref(f)); //std::thread t1(factorial,4,std::ref(x));
p.set_value(4);//如果使用了promise而没有set_value,此时子线程 //f.get()将抛出一个std::future_error::broken_promise //的异常
x = fu.get(); cout << "get from child thread:" << x << endl; //t1.join(); return 0; } |
执行结果,可以看出子线程的结果为24,主线程也显示出对应的子线程中的结果。
注意:promise和future不可以使用copy,但是可以使用move,
Std::promise<int> p2=p; //这是错误的
但是
Std::promise<int >p2=std::move(p);//这是正常的,可是使用的。
假如主线程中的factorial需要执行多次,能否可以创建对于很多线程的同步问题,可以创建多个
可以使用share_future
•假设,你有一个需要长时间的运算,你需要其能计算出一个有效的值,但是你现在并不迫切 需要这个值。你可以启动一个新线程来执行这个计算,但是这就意味着你必须关注如何传回计算的结
_