简体   繁体   English

C ++事件管理器多线程可靠吗?

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

i making class event manager like below EventManager.h 我使像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 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));
}

Calling 调用

//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();

Algorithm: When add function called, the function will add the struct and create new thread for delay cycle, the thread will move to vector, the thread will change flag of event for next execute on event main thread. 算法:调用添加函数时,该函数将添加结构并创建新线程以延迟周期,该线程将移至向量,该线程将更改事件标志,以供下一次在事件主线程上执行。

The problem: The problem is often that the thread for delay is not successful created, so the event is not called. 问题:问题通常是延迟线程未成功创建,因此未调用该事件。 How to fix it? 如何解决?

Using this_thread::sleep_for() inside a timer function is not advisable, and you are likely to miss a trigger point during the sleep cycle. 不建议在计时器函数中使用this_thread :: sleep_for(),并且您可能会在睡眠周期中错过触发点。 Excessive polling for the trigger point will also result in unnecessary wasted of CPU cycles. 对触发点的过多轮询也会导致不必要的CPU周期浪费。 So you should rely mainly on condition_variables that trigger at the exact time without polling. 因此,您应该主要依赖在准确时间触发而不轮询的condition_variables。

For example you can push a std::pair<time_point,thread_id> in an ordered container sorted in chronological order. 例如,您可以将std::pair<time_point,thread_id>推入按时间顺序排序的有序容器中。 Also see if priority queue could suit your needs. 另请参阅优先级队列是否可以满足您的需求。 Your routine is overly complicated, simplicity has its own quality. 您的例程过于复杂,简单有其自身的品质。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM