美文网首页
C++ call_once和condition_variable

C++ call_once和condition_variable

作者: 土豆吞噬者 | 来源:发表于2019-09-26 21:34 被阅读0次

只调用一次

有些功能我们只需要或者必须只调用一次,在单线程环境下,通过判断一个bool flag即可:

bool g_inited;

int main()
{
    if (!g_inited) {
        g_inited = true;
        //...init
    }
    system("pause");
}

而在多线程环境下,这些只需要调用一次的功能有可能会被多次调用,你可以使用mutex来避免多次调用,但C++标准库提供了一种更方便的方法,下面的init函数只会被调用一次。

call_once调用的函数如果发生异常会被call_once抛出,并且这次调用被视为不成功,下一次call_once还可以再调用函数。

once_flag initFlag;

void init()
{
    cout << "init" << endl;
}
 
void threadProc()
{
    call_once(initFlag, init);
}

int main()
{
    thread(threadProc).detach();
    thread(threadProc).detach();
    thread(threadProc).detach();
    thread(threadProc).detach();
    system("pause");
}
 

条件变量

有时候不同线程之间需要彼此等待对方的数据才能进行下一步操作,最简单粗暴的方法是轮询是否有数据,期间还要使用mutex进行同步,这种方式效率很低,更好的办法是使用C++标准库中的condition_variable来同步线程之间的数据流逻辑依赖关系。

上述问题最典型的场景是生产者-消费者模型,当生产者产生数据后,调用notify_one方法唤醒等待中的线程,或调用notify_all方法唤醒所有等待中的线程,而消费者调用wait方法等待。

为了等待condition_variable,你需要一个mutex和一个unique_lock用来同步wait,wait内部会锁定或解锁mutex,所有等待某个condition_variable的线程都必须使用相同的mutex。

condition_variable有可能存在假醒的情况,因此等待完成后不一定代表有数据产生了,你需要再去验证一次是否有数据。

condition_variable的wait方法总是在锁住的mutex基础上操作,调用wait方法时,会解锁mutex然后进入等待状态,等到数据后会再次锁定mutex。如果要指定等待时间,可以使用wait_for,wait_until。

下面是一个简单的生产者-消费者代码,provider每隔200毫秒push一个数据到队列,完成后调用notify_one唤醒消费者线程,消费者线程等待唤醒后输出数据。

#include <condition_variable>
using namespace std;

queue<int> g_queue;
mutex g_mutex;
condition_variable g_queueConditionVariable;

void provider(int baseNumber)
{
    for (int i = 0; i < 10; ++i) {
        {
            lock_guard<mutex> lockGuard(g_mutex);
            g_queue.push(baseNumber + i);
        }
        g_queueConditionVariable.notify_one();
        this_thread::sleep_for(chrono::microseconds(200));
    }
}

void consumer(int id)
{
    while (true) {
        unique_lock<mutex> uniqueLock(g_mutex);
        g_queueConditionVariable.wait(uniqueLock, [] {return !g_queue.empty(); });
        cout << "consumer" << id << ":" << g_queue.front() << endl;
        g_queue.pop();
    }
}

int main()
{
    thread(provider, 1).detach();
    thread(provider, 10).detach();
    thread(provider, 100).detach();
    thread(consumer, 1).detach();
    thread(consumer, 2).detach();
    cin.get();
}

相关文章

  • C++ call_once和condition_variable

    只调用一次 有些功能我们只需要或者必须只调用一次,在单线程环境下,通过判断一个bool flag即可: 而在多线程...

  • condition_variable介绍

    std::condition_variable std::condition_variable是条件变量。 [Li...

  • C++ 并发编程学习(九)

    保护共享数据的替代设施 一. std::once_flag 和 std::call_once 二. 一个 std:...

  • std::condition_variable 详解

    头文件主要包含了与条件变量相关的类和函数。相关的类包括 std::co...

  • C+++ 多线程

    C++11线程编程的内容 thread、mutux、atomic、condition_variable、uniqu...

  • C++ 线程锁

    多线程共享数据线程锁 std::condition_variable 等待一个条件的满足

  • once_flag和call_once的简单实现

    once_flag 和 call_once 用于保证某个函数能够只执行一次,能够解决类似与单例模式中懒汉方式构建对...

  • C++实现 生产者消费者模型

    condition_variable条件变量可以用来实现线程同步,它必须与互斥量mutex配合使用。条件变量适用场...

  • std::call_once的使用

    一、背景 有时候我们需要在第一次执行某个函数时进行一个特定的操作specifiedOperation,后面就不再执...

  • C++学习笔记目录

    C++初步 C++数据长度 C/C++ 堆 栈 静态 常量 代码 区 static关键字 C++类和对象 C++引...

网友评论

      本文标题:C++ call_once和condition_variable

      本文链接:https://www.haomeiwen.com/subject/ocmryctx.html