future promise async
从父线程获取子线程的变量
假设有一个函数计算阶乘
void factorial(int N) {
int res = 1;
for (int i = N; i > 1; --i)
res *= i;
std::cout << "result is:" << res << std::endl;
}
int main() {
std::thread t1(factorial,4);
t1.join();
return 0;
}
如果需要把结果返回,按照现有的知识,应该是用下面的方法
std::mutex mu;
std::condition_variable cond;
void factorial(int N,int& x) {
int res = 1;
for (int i = N; i > 1; --i)
res *= i;
std::cout << "result is:" << res << std::endl;
std::unique_lock<std::mutex> locker(mu);
x = res;
locker.unlock();
cond.notify_one();
}
int main() {
int x=0;
std::thread t1(factorial,4,std::ref(x));
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker);
std::cout << x << std::endl;
t1.join();
return 0;
}
这样还是很麻烦。标准库给出了解决方案,即使用std::async返回一个future变量。
get()
方法会等待子线程结束后,返回子线程的结果。
#include <future>
int factorial(int N) {
int res = 1;
for (int i = N; i > 1; --i)
res *= i;
std::cout << "result is:" << res << std::endl;
return res;
}
int main() {
int x=0;
std::future<int> fu = std::async(factorial, 4);
x = fu.get();
std::cout << x << std::endl;
return 0;
}
get()
方法只能调用一次
async
不一定创建子线程,取决于第一个参数
std::async(std::launch::async|std::launch::deferred,factorial, 4);
不写的话,默认的是上面的方式。其中deferred参数不会创建子线程,而async方法会创建子线程
int factorial(int N) {
int res = 1;
for (int i = N; i > 1; --i)
res *= i;
std::cout << "result is: " << res <<" at "<<std::this_thread::get_id()<< std::endl;
return res;
}
int main() {
int x=0;
std::future<int> fu = std::async(std::launch::deferred,factorial, 4);
x = fu.get();
std::cout << "x: " << x << " id: " << std::this_thread::get_id() << std::endl;
return 0;
}
int factorial(int N) {
int res = 1;
for (int i = N; i > 1; --i)
res *= i;
std::cout << "result is: " << res <<" at "<<std::this_thread::get_id()<< std::endl;
return res;
}
int main() {
int x=0;
std::future<int> fu = std::async(std::launch::async,factorial, 4);
x = fu.get();
std::cout << "x: " << x << " id: " << std::this_thread::get_id() << std::endl;
return 0;
}
子线程获取父线程的变量
int factorial(std::future<int>& f) {
int res = 1;
int N = f.get();
for (int i = N; i > 1; --i)
res *= i;
std::cout << "result is: " << res <<" at "<<std::this_thread::get_id()<< std::endl;
return res;
}
int main() {
int x=0;
std::promise<int> p;
std::future<int> f = p.get_future();
std::future<int> fu = std::async(std::launch::async,factorial, std::ref(f));
p.set_value(4);
x = fu.get();
std::cout << "x: " << x << " id: " << std::this_thread::get_id() << std::endl;
return 0;
}
如果需要多个子线程获取同一个父线程中的变量,可以使用std::shared_future
std::mutex mu;
int factorial(std::shared_future<int> f) {
int res = 1;
int N = f.get();
for (int i = N; i > 1; --i)
res *= i;
std::lock_guard<std::mutex> lock(mu);
std::cout << "result is: " << res <<" at "<<std::this_thread::get_id()<< std::endl;
return res;
}
int main() {
int x=0;
std::promise<int> p;
std::future<int> f = p.get_future();
std::shared_future<int> sf = f.share();
std::future<int> fu1 = std::async(std::launch::async, factorial, sf);
std::future<int> fu2 = std::async(std::launch::async, factorial, sf);
std::future<int> fu3 = std::async(std::launch::async, factorial, sf);
p.set_value(4);
x = fu1.get();
mu.lock();
std::cout << "x: " << x << " id: " << std::this_thread::get_id() << std::endl;
mu.unlock();
x = fu2.get();
mu.lock();
std::cout << "x: " << x << " id: " << std::this_thread::get_id() << std::endl;
mu.unlock();
x = fu3.get();
mu.lock();
std::cout << "x: " << x << " id: " << std::this_thread::get_id() << std::endl;
mu.unlock();
return 0;
}
使用可调用对象
class A {
public:
void f(int x,char c){}
int operator()(int N) { return 0; }
};
void foo(int x){}
int main() {
A a;
std::thread t1(a, 6);//传递a的拷贝给子线程
std::thread t2(std::ref(a), 6);//传递a的引用给子线程
std::thread t3(std::move(a), 6);//传递a给子线程
std::thread t4(A(), 6);//传递临时创建的A对象给子线程
std::thread t5(foo, 6);//函数
std::thread t6([](int x) {return x*x; }, 6);//lambda函数
std::thread t7(&A::f, a, 8, 'w');//传递a的拷贝的成员函数给子线程
std::thread t8(&A::f, &a, 8, 'w');//传递a的地址的成员函数给子线程
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
t8.join();
return 0;
}
package_task
std::package_task
包装一个可调用对象,并允许异步获取该可调用对象产生的结果。它将包装的可调用对象的结果传递给一个std::future
对象(该对象通常在另一个线程中获取std::package_task
的执行结果)
int factorial(int N) {
int res = 1;
for (int i = N; i > 1; --i)
res *= i;
std::cout << "result is:" << res << std::endl;
return res;
}
std::deque<std::packaged_task<int()>> task_q;
std::mutex mu;
std::condition_variable cond;
void thread_1(){
std::packaged_task<int()> t;
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, []() {return !task_q.empty(); });
t = std::move(task_q.front());
}
t();
}
int main() {
std::thread t1(thread_1);
std::packaged_task<int()> t(std::bind(factorial,4));
std::future<int> ret = t.get_future();
{
std::unique_lock<std::mutex> locker(mu);
task_q.push_back(std::move(t));
}
cond.notify_one();
int value = ret.get();
std::cout << value << std::endl;
t1.join();
return 0;
}
时间限制
int factorial(int N) {
int res = 1;
for (int i = N; i > 1; --i)
res *= i;
std::cout << "result is:" << res << std::endl;
return res;
}
int main() {
std::thread t1(factorial,4);
//线程的时间限制
std::this_thread::sleep_for(std::chrono::milliseconds(3));
//上面的代码和下面的有相同的效果
std::chrono::steady_clock::time_point tp = std::chrono::steady_clock::now() + std::chrono::milliseconds(3);
std::this_thread::sleep_until(tp);
t1.join();
//锁的时间限制
std::mutex mu;
std::unique_lock<std::mutex> locker(mu);
locker.try_lock_for(std::chrono::milliseconds(3));
locker.try_lock_until(tp);
//条件变量的时间限制
std::condition_variable cond;
cond.wait_for(locker, std::chrono::milliseconds(3));
cond.wait_until(locker, tp);
//future变量的时间限制
std::promise<int> p;
std::future<int> f = p.get_future();
f.wait_for(std::chrono::milliseconds(3));
f.wait_until(tp);
return 0;
}