线程内队列的关键部分

critical section for a queue inside a thread

本文关键字:键部 队列 线程      更新时间:2023-10-16

我有一个单例事件类,上面有一个队列和线程。实现就像,有几个模块/对象订阅某些事件并能够发布多个事件。

此事件类的目的是在将其推送到队列时接收所有这些事件,并且此类中的线程需要弹出事件并将其发送到相应的订阅模块/对象。

背后的想法是创建一个基于 c++ 的事件聚合器,它可以在 C# 上使用。

实现就像

    void c_eventAggregator::PostEvent(EVENT_UID EventUid)
{
    c_criticalRegion criticalRegion(eASyncObj);
    Queue.push_back(EventUid);
    criticalRegion.~c_criticalRegion();
}
void c_eventAggregator::DispatchEventToClients(EVENT_UID EventUid)
{
    EventClientsList eclist = _eventIdSubsList[EventUid];
    for (EventClientsList::iterator iter = eclist.begin(); iter != eclist.end(); iter++) {
        iter->second->receiveEvent(EventUid);
    }
}
int c_eventAggregator::SubscribeEvent(EVENT_CLIENTID clientId, c_eventClient *ecPtr, EVENT_UID EventUid)
{
    try
    {
        _eventIdSubsList[EventUid].insert(make_pair(clientId, ecPtr));
    }
    catch (int exception)
    {
        return exception;
    }
    return ZERO_VALUE;
}
void c_eventAggregator::run(void)
{
    EVENT_UID EventUid;
    while (isAlive())
    {
        while (Queue.size())
        {
            if (!Queue.empty())
            {
                c_criticalRegion criticalRegion(eASyncObj);
                EventUid = Queue[0];
                Queue.pop_front();
                DispatchEventToClients(EventUid);
                criticalRegion.~c_criticalRegion();
            }
        }
    }
}

我在推送和弹出之间使用关键部分,以便在多个模块/对象同时写入时队列不会被覆盖。(不确定这是否正确)。

我的关键部分处理程序就像

class c_criticalRegion{
  public:
    c_criticalRegion(c_syncObject &paSyncObject) : mSyncObject(paSyncObject){
      mSyncObject.lock();
    }
    ~c_criticalRegion(){
      mSyncObject.unlock();
    }
  private:
    c_syncObject &mSyncObject;
};
同步

对象类似于同步.cpp,

c_syncObject::c_syncObject(){
    InitializeCriticalSection(&m_oMutexHandle);
}
c_syncObject::~c_syncObject(){
    DeleteCriticalSection(&m_oMutexHandle);
}

同步.h:

class c_syncObject{
private:
protected:
    //! The win32 CRITICAL_SECTION handle of the operating system.
    CRITICAL_SECTION m_oMutexHandle;
public:
    c_syncObject();
    ~c_syncObject();
    /*!brief Lock the resource coming after the lock command
    *
    * This function blocks until it will get the lock for the coming critical section.
    */
    void lock(void){
        EnterCriticalSection(&m_oMutexHandle);
        //TODO handle return value
    };
    //!Free the resource coming after the lock command  
    void unlock(void){
        LeaveCriticalSection(&m_oMutexHandle);
        //TODO handle return value
    };
};

我在这里面临的问题是,除非我在 PostEvent() 中注释criticalRegion.~c_criticalRegion(),否则代码有时不起作用。同样,当有事件发送到 PostEvent 时,run()内的队列仍显示大小为零。

这有点微不足道,我最终在其他具有类似实现的文件上也会遇到相同的情况。

我也想知道,当发布关键部分时,在完成任务后DispatchEventToClients()或之前。

在这种情况下,

您不能显式调用析构函数。实际上,你应该称之为它的情况很少,你可能永远不会面对其中之一(我一生中只有一个,这是一个肮脏的黑客)。

这是你的问题:

void c_eventAggregator::PostEvent(EVENT_UID EventUid)
{
    c_criticalRegion criticalRegion(eASyncObj);
    Queue.push_back(EventUid);
    criticalRegion.~c_criticalRegion();    // <<< this is wrong
}

通过此代码criticalRegion析构函数将被调用两次 - 一次由您调用,一次由编译器调用。

这种类称为守卫,它们可以帮助您避免显式调用"清理"(在您的情况下LeaveCriticalSection)。在您的情况下,这没什么大不了的,但有时功能中有很多return,把它放在任何地方都是一团糟。并且在发生异常时不会调用显式调用。

您可以使用显式调用和不带显式调用来检查简单示例