C++ 我应该按什么顺序发送callback()&;通知服务员?
我有一个类,通过它我可以异步提供一些服务(同样的调用也可以同步进行)。当被请求时,该类的对象(比如操作符)在不同的线程中启动该操作。其他对象可以注册到operator对象的通知,以便在操作结束时对该对象调用OperationEnded()方法。其他对象也可以通过调用操作符对象上的wait()来等待此操作的完成 操作结束时的代码大致如下:C++ 我应该按什么顺序发送callback()&;通知服务员?,c++,multithreading,thread-safety,C++,Multithreading,Thread Safety,我有一个类,通过它我可以异步提供一些服务(同样的调用也可以同步进行)。当被请求时,该类的对象(比如操作符)在不同的线程中启动该操作。其他对象可以注册到operator对象的通知,以便在操作结束时对该对象调用OperationEnded()方法。其他对象也可以通过调用操作符对象上的wait()来等待此操作的完成 操作结束时的代码大致如下: _opEndedMutex.lock(); _thereIsOngoingOp = false; _opEndedCondition.notify_all();
_opEndedMutex.lock();
_thereIsOngoingOp = false;
_opEndedCondition.notify_all();
_opEndedMutex.unlock();
//no more call after notification
m_spNotificationManager->OperationEnded();
boost::unique_lock<boost::mutex> lock(_opEndedMutex);
while(_thereIsOngoingOp)
{
_opEndedCondition.wait(_opEndedMutex);
}
wait()函数如下所示:
_opEndedMutex.lock();
_thereIsOngoingOp = false;
_opEndedCondition.notify_all();
_opEndedMutex.unlock();
//no more call after notification
m_spNotificationManager->OperationEnded();
boost::unique_lock<boost::mutex> lock(_opEndedMutex);
while(_thereIsOngoingOp)
{
_opEndedCondition.wait(_opEndedMutex);
}
还要注意,操作符对象是可重用的。客户端代码可以使新的运算符对象多次使用它,并在最后将其删除。对此,您有几种解决方案:
- 可以从中专门化操作对象。这意味着在客户机代码中,您不再删除对象,而是将std::shared_ptr设置为nullptr,而不关心对象何时被实际删除
- 您可以在计时器延迟上实现有限的垃圾收集:当您在客户机代码中收到
通知时,将指针与添加对象的时间戳一起放在队列中。然后,队列将有一个活动对象,该对象在计时器上唤醒,以当前时间为准,如果时间戳(比方说)比当前时间至少早五秒,则将其删除OperationEnded()
- 您可以使用分配和取消分配操作类。当一个对象不再使用时,它实际上不会被删除,而是作为一个自由(回收)对象放置在池中。在您完成处理后,当池被销毁时,对象实际上会被删除
- 您可以为您的对象创建生命周期管理器,该管理器将删除您的操作对象,然后发送通知
- 您可以进行“OperationEnded”函数调用
删除此项代码>在末尾;然后,您将实现客户端代码,以便在接收通知时将指针设置为NULL;不过,这样的解决方案很脆弱,而且在您的实现中,这可能只是将问题转移到另一段代码上
- 最后,您可以实现所有这些的自定义组合
经验教训:尽可能只提供一个通知机制。
只需要C++,或者我需要发布一些与C语言相关的代码?真正的问题在于资源管理,所以C不会太多相关。谢谢几个好主意,这些给了我一个很好的方向。我还编辑了这个问题,以提供有关API的更多信息。逐一评估您的报价。1-我无法控制所有的客户端代码(有这么多),因此这方面的任何解决方案都是不可能的。将API作为共享的ptr分发会很好,但是这里的任何更改都是不可接受的-我也不太喜欢用我的API分发boost版本。事实上,这本身是不够的,我们还应该自己保留shred_ptr以防止早期删除,并在某个点将其设置为null,这是最初的问题2-这是一个好的方向,但仍然会有一场竞赛。如果这个删除是通过一些同步手段而不是延迟来完成的,我可以接受这个解决方案。我认为这是最好的候选人。3-对象池会很好。但这仍然留下了一个问题,即我应该在没有争用/崩溃的情况下准确地删除对象。4-对象是可重用的。因此,这是不可接受的。对不起,我会将此信息添加到问题中。5-我无法修改客户端代码。OperationEnded()在客户端被覆盖。6-我认为结合一些线程安全措施的第二个选项会很好。对于解决方案2,您需要保留一个要删除的指针列表。当您向列表中添加POINER(和时间戳)(要删除)、从列表中读取指针和时间戳以及从列表中删除它们(如果给定的超时已过)时,需要同步此列表。延迟机制是一种避免删除冲突的方法(即,如果线程在调用OperationEnded()
后(平均)1秒完成,则应在大约10秒后删除添加的指针。运算符对象是可重用的。其中一些对象可能会存活数月(该库也用于服务器机器).因此,拖延时间和希望避免冲突不适合这个库。