操作结束时的代码大致如下:
_opEndedMutex.lock(); _thereIsOngoingOp = false; _opEndedCondition.notify_all(); _opEndedMutex.unlock(); //no more call after notification m_spNotificationManager->OperationEnded();
而wait()函数如下:
boost::unique_lock<boost::mutex> lock(_opEndedMutex); while(_thereIsOngoingOp) { _opEndedCondition.wait(_opEndedMutex); }
问题在于资源管理.这是一个C类,因此当检测到操作结束时,此类的用户可能会删除操作符对象(如果有任何活动操作,析构函数将等待完成).可以通过等待或接受通知来检测操作的结束.因此,如果我首先调用_opEndedCondition.notify_all()并且用户删除操作符对象,则在尝试调用OperationEnded()时可能会崩溃,因为m_spNotificationManager已被删除.如果选择首先调用OperationEnded()并且用户在此调用期间删除操作符对象,则在尝试访问_opEndedMutex,_thereIsOngoingOp和_opEndedCondition时可能会崩溃.
我想到的第一件事就是使用新的互斥锁来保护这两个调用.这看起来并不漂亮,因为我无法预见如果引入新的互斥锁会发生什么,并且如果在OperationEnded()通知中用户同步启动新操作.我也不确定如何在wait()方法中使用新的互斥锁.
注1:此API用于我们自己公司和其他公司的应用程序.所以我无法摆脱任何一种同步机制.
注意2:我修改了原始代码,变量和方法名称,因此可能存在拼写错误,但这个想法应该是明确的.
EDIT1:
运算符对象保留在通过工厂生成的共享库中,然后通过接口暴露给外部世界.
所以操作符对象的典型生命周期如下:
IOperator * op = factory:getNewOperator(); //perform operations with op op->Release() //this one goes and deletes the op object
解决方法
>您可以从std::enable_shared_from_this专门化您的操作对象.这意味着在客户端代码中,您不再删除该对象,而是将std :: shared_ptr设置为nullptr,并且在实际删除对象时不关心.
>您可以在计时器延迟时实现有限的垃圾收集:当您在客户端代码中收到OperationEnded()通知时,您将获取指针并将其放在队列中,以及添加对象时的时间戳.然后队列将有一个活动对象在计时器上唤醒,占用当前时间,如果时间戳(比如说)比当前时间至少早五秒,则删除它.
>您可以使用object pool分配和取消分配操作类.当不再使用某个对象时,它实际上不会被删除,而是作为池中的免费(回收)对象放置.在完成处理后,当池被销毁时,实际上将删除该对象.>您可以为对象创建生命周期管理器,这将删除您的操作对象,然后发送通知.>你可以让’OperationEnded’函数调用删除这个;在末尾;然后,您将实现客户端代码,以便在接收通知时将指针设置为NULL;这样的解决方案虽然很脆弱,但实际上,这可能会将问题转移到另一段代码中.>最后,您可以实现所有这些的自定义组合.