在多线程程序中,线程同步(多个线程访问一个资源保证顺序)是一个非常重要的问题,Linux下常见的线程同步的方法有下面几种:

  • 互斥锁
  • 条件变量
  • 信号量

这篇博客只介绍互斥量和条件变量的使用。

互斥锁和条件变量

通常情况下,互斥锁和条件变量是配合使用的,互斥锁用于短期锁定,主要保证线程对临界区的进入;条件变量用于线程长期等待,在wait的时候会释放锁。操作的API如下所示(介绍最常用的):

std::mutex : 独占的互斥量,不能递归使用
std::condition_variable :条件变量,配合 std::unique<std::mutex>进行wait操作。
std::condition_variable_any 和任意带有lock,unlock的mutex配合使用,但是效率比std::condition_variable差。

举个栗子:

10个人排队使用打印机,任一时刻只有一个人能使用。用一个变量i01两种状态分别表示打印机能不能使用。这个程序这样写,详细解释见注释:

#include<iostream>
#include<condition_variable>
#include<vector>
#include<thread>

std::vector<std::thread> tv;         //保存线程的情况
std::condition_variable_any m_t;     //条件变量
std::mutex lock;                     //互斥锁
int i = 1;                           //打印机资源 初始为1 表示可用


void subi() {            
    std::lock_guard<std::mutex> locker(lock);  //使用之前先加锁
    while(i == 0){             //如果不可用                
        m_t.wait(lock);        //将当前线程阻塞,注意:此时会释放锁
    }

    i--;                       //使用打印机过程
}

void addi() {                 
    std::lock_guard<std::mutex> locker(lock); //同理,放弃使用的时候先加锁

    i++;                       //是资源变为可用
    m_t.notify_all();          //通知其余阻塞的使用者可以使用了
}

void func(int j) {
    subi();
    std::cout << "I am thread "<< j << " , i = " << i << std::endl;
    addi();
}


int main(int argc,char *argv[])
{
    for(int j = 0; j < 10 ; ++j) {
        std::thread t(func,j);
        tv.push_back(std::move(t));
    }

    for(auto &thread : tv) {
        thread.join();
    }
    return 0;
}

测试情况应该是:每个进程输出的i都为0,表示每个进程都在合理的使用打印机,没有出现同时使用的情况,即i < 0的情况。

$ g++ condition.cpp -pthread //注意链接pthread

这里写图片描述

嗯,可见我们的使用姿势是正确的~

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐