线程同步主要是为了解决对共享数据的竞争访问问题,所以线程同步主要是对共享数据的访问同步化(按照既定的先后次序,一个访问需要阻塞等待前一个访问完成后才能开始)。这篇文章谈到的异步编程主要是针对任务或线程的执行顺序,也即一个任务不需要阻塞等待上一个任务执行完成后再开始执行,程序的执行顺序与任务的排列顺序是不一致的。下面从任务执行顺序的角度解释下同步与异步的区别:
同步:就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。 异步:调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
如何使用异步编程
在线程库< thread >中并没有获得线程执行结果的方法,通常情况下,线程调用者需要获得线程的执行结果或执行状态,以便后续任务的执行。那么,通过什么方式获得被调用者的执行结果或状态呢?
1 使用全局变量与条件变量传递结果
前面谈到的条件变量具有“通知–唤醒”功能,可以把执行结果或执行状态放入一个全局变量中,当被调用者执行完任务后,通过条件变量通知调用者结果或状态已更新,可以使用了。下面给出一个程序示例:
//future1.cpp 使用全局变量传递被调用线程返回结果,使用条件变量通知调用线程已获得结果
#include <vector>
#include <numeric>
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
int res = 0; //保存结果的全局变量
std::mutex mu; //互斥锁全局变量
std::condition_variable cond; //全局条件变量
void accumulate(std::vector<int>::iterator first,
std::vector<int>::iterator last)
{
int sum = std::accumulate(first, last, 0); //标准库求和函数
std::unique_lock<std::mutex> locker(mu);
res = sum;
locker.unlock();
cond.notify_one(); // 向一个等待线程发出“条件已满足”的通知
}
int main()
{
std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };
std::thread work_thread(accumulate, numbers.begin(), numbers.end());
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, [](){ return res;}); //如果条件变量被唤醒,检查结果是否被改变,为真则直接返回,为假则继续等待
std::cout << "result=" << res << '\n';
locker.unlock();
work_thread.join(); //阻塞等待线程执行完成
getchar();
retur