我有一个单例事件类,其上有一个队列和线程。实现就像,有几个模块/对象订阅某些事件并能够发布多个事件。
此事件类的目的是在队列上推送它时接收所有这些事件,并且此类中的线程需要弹出事件并将其发送到相应的订阅模块/对象。
背后的想法是创建一个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);
}
synch.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()
之后或之前发布关键部分时。
答案 0 :(得分:1)
在这种情况下,你不能明确地调用析构函数。实际上,你应该打电话的情况很少,你可能永远不会面对其中一个(我生命中只有一个,这是一个肮脏的黑客)。
这是你的问题:
void c_eventAggregator::PostEvent(EVENT_UID EventUid)
{
c_criticalRegion criticalRegion(eASyncObj);
Queue.push_back(EventUid);
criticalRegion.~c_criticalRegion(); // <<< this is wrong
}
通过此代码criticalRegion
析构函数将被调用两次 - 一次由您调用,一次由编译器调用。
这类课程称为警卫,它们可以帮助您避免明确要求清理&#34; (在你的情况下LeaveCriticalSection
)。在你的情况下,它并不是什么大不了的事,但有时会有很多return
的功能,而且把它放到任何地方都很麻烦。如果出现异常,则不会调用显式调用。
您可以查看简单示例with explicit call和w/o explicit call