编程代码
新闻详情

C++ 线程间同步

发布时间:2021-03-29 09:36:33 最后更新:2021-03-30 09:02:29 浏览次数:2822

0 前言

  • 多线程在运行过程中,各个线程都是随着 OS 的调度算法,占用 CPU 时间片来执行指令做事情,每个线程的运行完全没有顺序可言。
  • 在某些应用场景下,一个线程需要等待另外一个线程的运行结果,才能继续往下执行,这就涉及到线程之间的同步通信机制。
  • 线程间同步通信最典型的例子就是生产者-消费者模型,生产者线程生产出产品以后,会通知消费者线程去消费产品;当消费者线程去消费产品时,发现还没有产品生产出来,它需要通知生产者线程赶快生产产品,等生产者线程生产出产品以后,消费者线程才能继续往下执行。

1 消费者“被动等待”

#include 
#include 
#include 

static std::mutex mtx;
static std::deque<int> dq;
static int productNum = 5;

void Producer()
{
    using namespace std::literals::chrono_literals;
    for (int i = 1; i <= productNum; ++i) {
        mtx.lock();
        dq.push_front(i);
        std::cout << "Producer 生产产品为: " << i << std::endl;
        mtx.unlock();
        // std::this_thread::sleep_for(1s);
    }
}

void Consumer()
{
    while (true) {
        if (dq.empty()) {
            continue;
        }
        mtx.lock();
        int data = dq.back();
        dq.pop_back();
        std::cout << "Consumer 消费产品为: " << data << std::endl;
        mtx.unlock();
    }
}

int main()
{
    std::thread t1(Producer);
    std::thread t2(Consumer);
    t2.join();
    t1.join();
    std::cin.get();
}

程序运行结果如下:

C++ 线程间同步

如果让生产者线程每生产一个产品后休息(sleep) 1s,结果如下:

C++ 线程间同步

解释:该例子中,生产者和消费者分别对应两个线程。队列中存在物品时,消费者去消费,否则空循环,一直等待。

缺点:当双端队列中没有物品时,消费者只会原地死等,不会去催。

2 消费者“主动出击”

#include 
#include 
#include 
#include 
#include 
  
std::mutex mtx;
std::condition_variable cv;
std::vector<int> vec;
int productNum = 5;

void Producer()
{
    for (int i = 1; i <= productNum; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        while (!vec.empty()) {
            cv.wait(lock); // vec 不为空时阻塞当前线程
        }
        vec.push_back(i);
        std::cout << "Producer生产产品: " << i << std::endl;
        cv.notify_all(); // 释放线程锁
    }
}

void Consumer()
{
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        while (vec.empty()) {
            cv.wait(lock); // vec 为空时等待线程锁。其他线程锁释放时,当前线程继续执行
        }
        int data = vec.back();
        vec.pop_back();
        std::cout << "Consumer消费产品: " << data << std::endl;
        cv.notify_all();
    }
}

int main()
{
    std::thread t1(Producer);
    std::thread t2(Consumer);
    t2.join();
    t1.join();
    std::cin.get();
}

程序运行结果如下:

C++ 线程间同步

解释:该例子中,生产者和消费者分别对应两个线程。只要 vector 中存在物品时,生产者线程就阻塞,通知消费者线程去消费;vector 中不存在物品时,消费者线程阻塞,通知生产者去生产。

3 线程加入方式 join 和 detach

join:采用 join 方式,t1、t2 乱序执行,且外层主线程会等到 t1、t2 都结束了再继续执行后面的代码。

detach:如果采用 detach 方式,t1、t2 乱序执行,且脱离了外层主线程。外层主线程执行结束时,t1、t2 可能还没结束,但此时程序就退出了。


如涉及侵权,请相关权利人与我司联系删除

在线客服 双翌客服
客服电话
  • 0755-23712116
  • 13822267203