c++11 多线程支持 条件变量(condition_variable_any)(一)

定义于头文件 <condition_variable>
class condition_variable_any;            (C++11 起) 

condition_variable_any 类是 std::condition_variable 的泛化。相对于只在 std::unique_lock<std::mutex> 上工作的 std::condition_variable , condition_variable_any 能在任何满足 基本可锁定 (BasicLockable) 要求的锁上工作。

条件变量语义描述见 std::condition_variable 。

std::condition_variable_any标准布局类型 (StandardLayoutType) 。它非 可复制构造 (CopyConstructible) 、 可移动构造 (MoveConstructible) 、 可复制赋值 (CopyAssignable) 或 可移动赋值 (MoveAssignable) 。

若锁是 std::unique_lock ,则 std::condition_variable 可能提供更好的性能。

构造函数

condition_variable_any();     (1) (C++11 起) 

condition_variable_any(const condition_variable_any&) = delete;
 (2) (C++11 起) 

1) 构造 std::condition_variable_any 类型对象。

2) 复制构造函数被删除。

参数                (无)

异常

1) 可能抛出 std::system_error ,其 std::error_condition 若线程无权限创建条件变量,则等于 std::errc::operation_not_permitted ,若非内存资源限制阻止此初始化,则等于 std::errc::resource_unavailable_try_again ,或其他实现定义值。

析构函数

~condition_variable_any();             (1) (C++11 起) 

销毁 std::condition_variable_any 类型对象。

若已通知所有线程,调用析构函数才是安全的。不要求它们已退出其对应的等待函数:一些线程仍然可等待重获得关联锁,或在重获得后等待被调度到运行。

一旦析构函数开始,程序员就必须确保没有线程试图等待在 *this 上,特别是在等待线程在循环中调用等待函数,或使用接收谓词的等待函数的重载时。

异常        (无)

通知一个等待的线程

void notify_one() noexcept;         (C++11 起) 

若任何线程在 *this 上等待,则调用 notify_one 会解阻塞等待线程之一。

参数                            (无)

返回值                        (无)

注意

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者(解锁+等待、唤醒和锁定)以能看做原子变量修改顺序单独全序发生:顺序对此单独的 condition_variable 是特定的。譬如,这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

通知线程不必保有等待线程所保有的同一互斥上的锁;实际上这么做是劣化,因为被通知线程将立即再次阻塞,等待通知线程释放锁。然而一些实现(尤其是许多 pthread 的实现)辨识此情形,在通知调用中,直接从条件变量队列转移等待线程到互斥队列,而不唤醒它,以避免此“急促并等待”场景。

然而,在要求精确调度事件时,可能必须在处于锁下时通知,例如,在若满足条件则线程将退出程序,导致析构通知线程的 condition_variable 的情况下。互斥解锁之后,但在通知前的虚假唤醒可能导致通知在被销毁对象上调用。

调用示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable_any cv;
std::mutex cv_m;
int i = 0;
bool done = false;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... \n";
    cv.wait(lk, [] {return i == 1;});
    std::cout << "...finished waiting. i == 1\n";
    done = true;
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying falsely...\n";
    cv.notify_one(); // 等待线程被通知 i == 0.
    // cv.wait 唤醒,检查 i ,再回到等待

    std::unique_lock<std::mutex> lk(cv_m);
    i = 1;
    while (!done)
    {
        std::cout << "Notifying true change...\n";
        lk.unlock();
        cv.notify_one(); // 等待线程被通知 i == 1 , cv.wait 返回
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lk.lock();
    }
}

int main()
{
    std::thread t1(waits), t2(signals);
    t1.join();
    t2.join();
}

输出

通知所有等待的线程

void notify_all() noexcept;         (C++11 起) 

解阻塞全部当前等待于 *this 的线程。

参数            (无)

返回值        (无)

注意

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者(解锁+等待、唤醒和锁定)以能看做原子变量修改顺序单独全序发生:顺序对此单独的 condition_variable 是特定的。譬如,这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

通知线程不必保有与等待线程所保有者相同互斥的锁;实际上这么做是劣化,因为被通知线程将立即再次阻塞,以等待通知线程释放锁。

调用示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable_any cv;
std::mutex cv_m; // 此互斥用于三个目的:
// 1) 同步到 i 的访问
// 2) 同步到 std::cerr 的访问
// 3) 为条件变量 cv
int i = 0;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cerr << "Waiting... \n";
    cv.wait(lk, [] {return i == 1;});
    std::cerr << "...finished waiting. i == 1\n";
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::cerr << "Notifying...\n";
    }
    cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}

int main()
{
    std::thread t1(waits), t2(waits), t3(waits), t4(signals);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

输出

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值