C++并发之条件变量(std::condition_variable)

1 概述

  条件变量是一个能够阻塞调用线程直到被通知恢复的对象。
  当调用其中一个等待函数时,它使用unique_lock(通过互斥锁)来锁定线程。线程保持阻塞状态,直到被另一个调用同一condition_variable对象上的通知函数的线程唤醒。
  条件变量类型的对象总是使用unique_lock来等待.
其类图如下:
类图

2 使用实例

struct Function4NotiryAll
{
    bool is_ready = false;
    std::mutex mutex;
    std::condition_variable cv;
    int counter = 0;

    void print_id(int id)
    {
        std::unique_lock<std::mutex> lock(mutex);
        while(!is_ready)
            cv.wait(lock);
        std::cerr << "id:" << id << std::endl;
        counter++;
    }

    void go()
    {
        std::unique_lock<std::mutex> lock(mutex);
        is_ready = true;
        cv.notify_all();
    }
};

void ConditionVariableSuite::notiry_all()
{
    std::thread threads[10];
    Function4NotiryAll function;

    for(int i = 0; i < 10; ++i)
        threads[i] = std::thread(&Function4NotiryAll::print_id, std::ref(function), i);
 
    function.go();
    for(auto & thread : threads)
        thread.join();

    TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3 接口使用

3.1 wait

struct Function4Wait
{
    volatile int cargo = 0;
    int counter = 0;
    std::mutex mutex;
    std::condition_variable cv;

    inline bool have_cargo() { return cargo != 0; }
    inline void consume_cargo() { cargo = 0; }

    void consume(int n)
    {
        for(int i = 0; i < n; i++)
        {
            std::unique_lock<std::mutex> lock(mutex);
            while(!have_cargo())
                cv.wait(lock);
            std::cerr << "cargo: " << cargo << std::endl;
            counter++;
            consume_cargo();
        }
    }

    void consume_with_predicate(int n)
    {
        for(int i = 0; i < n; i++)
        {
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock, std::bind(&Function4Wait::have_cargo, this));
            std::cerr << "cargo: " << cargo << std::endl;
            counter++;
            consume_cargo();
        }
    }

    inline void product(int n)
    {
        std::unique_lock<std::mutex> lock(mutex);
        cargo = n;
        cv.notify_one();
    }
};

void ConditionVariableSuite::wait()
{
    Function4Wait function;  
    std::thread thread[2];
    int n = 10;
    
    thread[0] = std::thread(&Function4Wait::consume, std::ref(function), 10);
    for(int i = 0; i < n; i++)
    {
        while(function.have_cargo())
            std::this_thread::yield();
        function.product(i + 1);
    }
    thread[0].join();
    TEST_ASSERT_EQUALS(true, function.counter == 10)

    function.counter = 0;
    thread[1] = std::thread(&Function4Wait::consume_with_predicate, std::ref(function), 10);
    for(int i = 0; i < n; i++)
    {
        while(function.have_cargo())
            std::this_thread::yield();
        function.product(i + 1);
    }
    thread[1].join();
    TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.2 wait_for

struct Function4WaitFor
{
    volatile int cargo = 0;
    int counter = 0;
    std::mutex mutex;
    std::condition_variable cv;

    inline bool have_cargo() { return cargo != 0; }
    inline void consume_cargo() { cargo = 0; }

    void consume(int n)
    {
        for(int i = 0; i < n; i++)
        {
            std::unique_lock<std::mutex> lock(mutex);
            while(!have_cargo() 
                && cv.wait_for(lock, std::chrono::seconds(1)) == std::cv_status::timeout)
                ;
            std::cerr << "cargo: " << cargo << std::endl;
            counter++;
            consume_cargo();
        }
    }

    void consume_with_predicate(int n)
    {
        for(int i = 0; i < n; i++)
        {
            std::unique_lock<std::mutex> lock(mutex);
            while(!cv.wait_for(lock, std::chrono::seconds(1), std::bind(&Function4WaitFor::have_cargo, this)))
                ;
            std::cerr << "cargo: " << cargo << std::endl;
            counter++;
            consume_cargo();
        }
    }

    inline void product(int n)
    {
        std::unique_lock<std::mutex> lock(mutex);
        cargo = n;
        cv.notify_one();
    }
};

void ConditionVariableSuite::wait_for()
{
    Function4WaitFor function;  
    std::thread thread[2];
    int n = 10;
    
    thread[0] = std::thread(&Function4WaitFor::consume, std::ref(function), 10);
    for(int i = 0; i < n; i++)
    {
        while(function.have_cargo())
            std::this_thread::yield();
        function.product(i + 1);
    }
    thread[0].join();
    TEST_ASSERT_EQUALS(true, function.counter == 10)

    function.counter = 0;
    thread[1] = std::thread(&Function4WaitFor::consume_with_predicate, std::ref(function), 10);
    for(int i = 0; i < n; i++)
    {
        while(function.have_cargo())
            std::this_thread::yield();
        function.product(i + 1);
    }
    thread[1].join();
    TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.3 wait_until

struct Function4WaitUntil
{
    volatile int cargo = 0;
    int counter = 0;
    std::mutex mutex;
    std::condition_variable cv;

    inline bool have_cargo() { return cargo != 0; }
    inline void consume_cargo() { cargo = 0; }

    void consume(int n)
    {
        for(int i = 0; i < n; i++)
        {
            std::unique_lock<std::mutex> lock(mutex);
            std::chrono::time_point<std::chrono::system_clock> timePoint 
                = std::chrono::system_clock::now() + std::chrono::seconds(1);
            while(!have_cargo() 
                && cv.wait_until(lock, timePoint) == std::cv_status::timeout)
                ;
            std::cerr << "cargo: " << cargo << std::endl;
            counter++;
            consume_cargo();
        }
    }

    void consume_with_predicate(int n)
    {
        for(int i = 0; i < n; i++)
        {
            std::unique_lock<std::mutex> lock(mutex);
            std::chrono::time_point<std::chrono::system_clock> timePoint 
                = std::chrono::system_clock::now() + std::chrono::seconds(1);
            while(!cv.wait_until(lock, timePoint, std::bind(&Function4WaitUntil::have_cargo, this)))
                ;
            std::cerr << "cargo: " << cargo << std::endl;
            counter++;
            consume_cargo();
        }
    }

    inline void product(int n)
    {
        std::unique_lock<std::mutex> lock(mutex);
        cargo = n;
        cv.notify_one();
    }
};

void ConditionVariableSuite::wait_until()
{
    Function4WaitUntil function;  
    std::thread thread[2];
    int n = 10;
    
    thread[0] = std::thread(&Function4WaitUntil::consume, std::ref(function), 10);
    for(int i = 0; i < n; i++)
    {
        while(function.have_cargo())
            std::this_thread::yield();
        function.product(i + 1);
    }
    thread[0].join();
    TEST_ASSERT_EQUALS(true, function.counter == 10)

    function.counter = 0;
    thread[1] = std::thread(&Function4WaitUntil::consume_with_predicate, std::ref(function), 10);
    for(int i = 0; i < n; i++)
    {
        while(function.have_cargo())
            std::this_thread::yield();
        function.product(i + 1);
    }
    thread[1].join();
    TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.4 notify_one

struct Function4NotityOne
{
    int cargo = 0;
    int counter = 0;
    std::mutex mutex;
    std::condition_variable produce;
    std::condition_variable consume;

    void consumer()
    {
        std::unique_lock<std::mutex> lock(mutex);
        while(cargo == 0)
            consume.wait(lock);
        std::cerr << "cargo: " << cargo << std::endl;
        cargo = 0;
        counter++;
        produce.notify_one();
    }
    void producer(int id)
    {
        std::unique_lock<std::mutex> lock(mutex);
        while(cargo != 0)
            produce.wait(lock);
        cargo = id;
        consume.notify_one();
    }
};
void ConditionVariableSuite::notify_one()
{
    std::thread consumers[10];
    std::thread producers[10];
    Function4NotityOne function;
    for(int i = 0; i < 10; ++i)
    {
        consumers[i] = std::thread(&Function4NotityOne::consumer, std::ref(function));
        producers[i] = std::thread(&Function4NotityOne::producer, std::ref(function), i + 1);
    }

    for(int i = 0; i < 10; ++i)
    {
        consumers[i].join();
        producers[i].join();
    }
    TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.5 notiry_all

struct Function4NotiryAll
{
    bool is_ready = false;
    std::mutex mutex;
    std::condition_variable cv;
    int counter = 0;

    void print_id(int id)
    {
        std::unique_lock<std::mutex> lock(mutex);
        while(!is_ready)
            cv.wait(lock);
        std::cerr << "id:" << id << std::endl;
        counter++;
    }

    void go()
    {
        std::unique_lock<std::mutex> lock(mutex);
        is_ready = true;
        cv.notify_all();
    }
    void allgo()
    {
        std::unique_lock<std::mutex> lock(mutex);
        is_ready = true;
        std::notify_all_at_thread_exit(cv, std::move(lock));
    }
};

void ConditionVariableSuite::notiry_all()
{
    std::thread threads[10];
    Function4NotiryAll function;

    for(int i = 0; i < 10; ++i)
        threads[i] = std::thread(&Function4NotiryAll::print_id, std::ref(function), i);
 
    function.go();
    for(auto & thread : threads)
        thread.join();

    TEST_ASSERT_EQUALS(true, function.counter == 10)
}

3.5 notify_all_at_thread_exit

void ConditionVariableSuite::notify_all_at_thread_exit()
{
    std::thread threads[10];
    Function4NotiryAll function;

    for(int i = 0; i < 10; ++i)
        threads[i] = std::thread(&Function4NotiryAll::print_id, std::ref(function), i);
 
    std::thread(&Function4NotiryAll::allgo, std::ref(function)).detach();
    for(auto & thread : threads)
        thread.join();

    TEST_ASSERT_EQUALS(true, function.counter == 10)   
}

说明:

  • notify_all_at_thread_exit 只能在线程中调用,在进程中调用将不起作用。
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励就是我最大的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值