gpt4 book ai didi

c++ - 线程内队列的临界区

转载 作者:行者123 更新时间:2023-11-28 05:51:59 30 4
gpt4 key购买 nike

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

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

背后的想法是创建一个基于 C++ 的 EventAggregator,它在 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();
}
}
}
}

我在 push 和 pop 之间使用临界区,这样当多个模块/对象同时写入时队列不会被覆盖。 (不确定这是否正确)。

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

class c_criticalRegion{
public:
c_criticalRegion(c_syncObject &paSyncObject) : mSyncObject(paSyncObject){
mSyncObject.lock();
}

~c_criticalRegion(){
mSyncObject.unlock();
}

private:
c_syncObject &mSyncObject;

};

同步对象就像sync.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() 中的 Queue 仍然显示大小为零。

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

另外我想知道,什么时候释放临界区,是在完成任务DispatchEventToClients()之后还是之前。

最佳答案

在这种情况下,您不能显式调用析构函数。实际上,您应该调用它的情况很少,您可能永远不会遇到其中一个(我一生中只有一个,而且是一个肮脏的 hack)。

这是你的问题:

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

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

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

您可以查看简单示例 with explicit callw/o explicit call

关于c++ - 线程内队列的临界区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35041780/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com