簡體   English   中英

具有std :: condition_variable的EventTask

[英]EventTask with std::condition_variable

我試圖使一個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;
};

嘗試這個:

#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為false並從循環中獲取面包,結束了它的線程。 請注意,這不會中斷工作程序功能,因為它已經在進行中-您必須等待(請注意調用析構函數進行join )才能完成它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM