美文网首页
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

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