簡體   English   中英

C ++事件管理器多線程可靠嗎?

[英]C++ Event Manager Multi-Thread Reliable?

我使像EventManager.h下面的類事件管理器

#ifndef EVENTMANAGER_H
#define EVENTMANAGER_H

#include <thread>
#include <mutex>
#include <chrono>
#include <atomic>
#include <condition_variable>
#include <vector>
#include "../../object/EObject.h"

class EventManager : public EObject {
public:
EventManager();
virtual ~EventManager();

int start_event();
void stop_event();

void add(const char* name, int interval, EObject * instance);

private:
static const int MAX_EVENT = 10;
std::atomic<int> event_total;

struct {
    int event_id;
    std::string event_name;
    int interval;
    std::atomic<bool> next_execute;
    EObject * instance;
    std::unique_ptr<std::condition_variable> cv;
    std::unique_ptr<std::mutex> mtx;
} my_event[MAX_EVENT];

std::thread * event_thread;
std::atomic<bool> shall_stop;
std::atomic<bool> has_stopped;
std::atomic<int> worker_delay;
void worker();

//timing
std::vector<std::unique_ptr<std::thread>> timing_work;
void timing(int id);
};

#endif /* EVENTMANAGER_H */

EventManager.cpp

#include <iostream>
#include "EventManager.h"
#include "../../object/EVariant.h"


using namespace std;

EventManager::EventManager() {
event_thread = nullptr;
has_stopped = true;
shall_stop = false;
worker_delay = 5; //milli second
event_total = 0;
}

EventManager::~EventManager() {
}

int EventManager::start_event() {
if (event_thread) {
    cout << "Event thread can not create\n" << flush;
    return -1;
} else {
    event_thread = new std::thread([this] {
        this->worker();
    });
    cout << "Event thread created\n" << flush;
}
return 0;
}

void EventManager::stop_event() {
shall_stop = true;
for (int i = 0; i < 5; i++) {
    this_thread::sleep_for(chrono::microseconds(10));

    if (has_stopped) break;
}
delete event_thread;
event_thread = nullptr;
}

void EventManager::worker() {
has_stopped = false;
while (1) {
    if (shall_stop) break;

    for (int i = 0; i < event_total; i++) {
        //            cout << "Event Manager: " << my_event[i].event_name << " - checking \n" << flush;
        if (my_event[i].next_execute) {
            EVariant var = EVariant();
            var.push("event_name", my_event[i].event_name);
            my_event[i].instance->update(var);
            my_event[i].next_execute = false;

            {
                condition_variable * cv = my_event[i].cv.get();
                mutex * mtx = my_event[i].mtx.get();
                unique_lock<mutex> lock(*mtx);
                cv->notify_one();
                //                    cout << "Event Manager: " << my_event[i].event_name << " - hey wakeup \n" << flush;
            }
        }
    }
    this_thread::sleep_for(chrono::milliseconds(worker_delay));
}
shall_stop = false;
has_stopped = true;
}

void EventManager::timing(int id) {
int _id = id;
cout << "Timing thread: " << my_event[_id].event_name << " - " << this_thread::get_id() << " - i was born\n" << flush;
while (1) {
    int delay = my_event[_id].interval;
    //        cout << "Event Manager: " << my_event[_id].event_name << " - i delay \n" << flush;
    this_thread::sleep_for(chrono::milliseconds(delay));

    my_event[_id].next_execute = true;

    {
        //            cout << "Event Manager: " << my_event[_id].event_name << " - i sleep \n" << flush;
        condition_variable * cv = my_event[_id].cv.get();
        mutex * mtx = my_event[_id].mtx.get();
        unique_lock<mutex> lock(*mtx);
        cv->wait(lock);
        //            cout << "Event Manager: " << my_event[_id].event_name << " - OK wakeup \n" << flush;
    }
}
cout << "Timing thread: " << id << " - i'm quit\n" << flush;
}

void EventManager::add(const char* name, int interval, EObject* instance)    {
cout << "Event adding : " << name << "\n" << flush;
event_total += 1;
int id = event_total - 1;
my_event[id].event_id = id;
my_event[id].event_name = name;
my_event[id].interval = interval;
my_event[id].instance = instance;
my_event[id].next_execute = false;

unique_ptr<mutex> mtx(new mutex());
my_event[id].mtx = std::move(mtx);

unique_ptr<condition_variable> cov(new condition_variable());
my_event[id].cv = std::move(cov);

//create thread delay
//    std::thread th([this] {
//        this->timing(event_total - 1);
//    });

unique_ptr<thread> thd(new thread([this] {
    this->timing(event_total - 1);
}));

//    timing_collection.push_back(std::move(th));
timing_work.push_back(std::move(thd));
}

調用

//event i2c communication
p_event_manager.emplace("I2C", new EventManager());
p_event_manager.at("I2C")->add("i2c_buffer", 10, pI2c.at("i2c-1"));
p_event_manager.at("I2C")->add("i2c_poll_tb", 30, p_touch_button.at("TouchButton1"));
p_event_manager.at("I2C")->add("i2c_micro_poll", 50, bsc_app);
p_event_manager.at("I2C")->start_event();

算法:調用添加函數時,該函數將添加結構並創建新線程以延遲周期,該線程將移至向量,該線程將更改事件標志,以供下一次在事件主線程上執行。

問題:問題通常是延遲線程未成功創建,因此未調用該事件。 如何解決?

不建議在計時器函數中使用this_thread :: sleep_for(),並且您可能會在睡眠周期中錯過觸發點。 對觸發點的過多輪詢也會導致不必要的CPU周期浪費。 因此,您應該主要依賴在准確時間觸發而不輪詢的condition_variables。

例如,您可以將std::pair<time_point,thread_id>推入按時間順序排序的有序容器中。 另請參閱優先級隊列是否可以滿足您的需求。 您的例程過於復雜,簡單有其自身的品質。

暫無
暫無

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

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