具有std :: condition_variable的EventTask

时间:2019-07-02 08:36:48

标签: c++ c++11

我正在尝试制作一个EventTask来调用循环中传递的函数。

我需要它等待开始,然后将其标记为完成。

我的问题是我不知道如何从我的等待函数中接收参数以传递给被调用的函数

您可以看到问题出在我的taskFunc _event.wait中,应将参数设置为传递给函数。

class Event
{
public:

    Event() : _signalled(false) {}

    virtual inline void notify(){
        std::unique_lock<std::mutex> lock(_mutex);
        _signalled = true;
        _condvar.notify_one();
    }

    virtual inline void wait(){
        std::unique_lock<std::mutex> lock(_mutex);
        _condvar.wait(lock, [&] { return _signalled; });
        _signalled = false;

        stop();
    }

    virtual inline void stop(){
        std::unique_lock<std::mutex> lock(_mutex);
        _signalled = false;
    }

private:

    std::mutex _mutex;
    std::condition_variable _condvar;
    bool _signalled;
};

template <class T>
class EventArg : public Event
{
public:

    virtual inline void notify(T arg){
        Event::notify();
        this->arg = arg;
    }

    virtual inline void wait(T& arg){
        Event::wait();
        arg = this->arg;
    }

private:
    T arg;
};

template<class... Args>
class EventTask
{
public:
    EventTask(std::function<void(Args...)> func) : m_Function(func), m_Run(true), m_thread(&taskFunc, this) {}

    void notify(Args&& ...Params) { 
        _Event.notify(std::forward<Args>(Params)...); }

    void wait() { 
        _EventFinished.wait(); }

    void stop() {
        m_stop = true;
        _Event.stop();
    }

private:
    void taskFunc()
    {
        void* pArg = nullptr;
        while (m_Run){
            _Event.wait(pArg);
            m_Function(std::forward<Args>(Params)...);
            _EventFinished.notify();
        }
    }

private:
    std::function<void(Args...)> m_Function;
    bool m_Run;
    std::thread m_thread;
    EventArg<Args...> _Event;
    Event _EventFinished;
};

1 个答案:

答案 0 :(得分:0)

尝试一下:

#include <iostream>
#include <functional>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <tuple>

template<class... Args>
class EventTask
{
public:
    EventTask(std::function<void(Args...)> func) : m_Function(func), m_Run(true) {
        m_thread = std::thread{ [=]() {
            taskFunc();
        }};
    }
    ~EventTask() {
        stop();
        m_thread.join();
    }

    void notify(const std::tuple<Args...> &args) {
        std::unique_lock<std::mutex> lock(_mutex);
        _signalled = true;
        _args = args;
        _condvar.notify_all();
    }

    void stop() {
        m_Run = false;
        _condvar.notify_all();
    }

private:
    void taskFunc()
    {
        std::tuple<Args...> args;
        while (true){
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _condvar.wait(lock, [&] { return m_Run && _signalled; });
                if (!m_Run) break;
                _signalled = false;
                args = _args;
            }
            std::apply(m_Function, args);
            //_EventFinished.notify();
        }
    }

private:
    std::function<void(Args...)> m_Function;

    std::tuple<Args...> _args;
    std::mutex _mutex;
    std::condition_variable _condvar;
    bool _signalled = false;

    //Event _EventFinished;
    bool m_Run;
    std::thread m_thread;
};

int main()
{
    EventTask<int, int> ma{ [](int a, int b) {

    }};
    ma.notify({ 1, 2 });
}

这是怎么回事?有两个线程,“生产者”线程(一个生产函数的参数,因此产生名称)和“消费者”线程(一个实际运行的线程)。

“生产者”线程锁定互斥锁,复制参数并通知,有事情要做。 “消费者”线程锁定互斥锁,然后等待条件。等待条件(和互斥体)会释放互斥体,当有关条件变量的通知到来时将需要该互斥体。当“生产者”变量设置参数时,“消费者”将醒来,重新获取互斥锁(这是必需的,否则,“生产者”可能会连续两次设置args导致竞争,这是未定义的行为),再次复制参数并释放互斥量。然后,继续使用它自己的本地参数副本调用worker函数。

当您尝试停止整个过程时,过程类似。 “生产者” 锁定互斥锁,将m_Run设置为false并通知所有人。 “消费者”线程醒来,通知m_Run为假,并从循环中获取面包,结束其线程。请注意,这不会中断工作程序功能,因为它已经在进行中-您必须等待(注意在析构函数中对join的调用)才能完成它。

相关问题