C++ 我应该按什么顺序发送callback()&;通知服务员?

C++ 我应该按什么顺序发送callback()&;通知服务员?,c++,multithreading,thread-safety,C++,Multithreading,Thread Safety,我有一个类,通过它我可以异步提供一些服务(同样的调用也可以同步进行)。当被请求时,该类的对象(比如操作符)在不同的线程中启动该操作。其他对象可以注册到operator对象的通知,以便在操作结束时对该对象调用OperationEnded()方法。其他对象也可以通过调用操作符对象上的wait()来等待此操作的完成 操作结束时的代码大致如下: _opEndedMutex.lock(); _thereIsOngoingOp = false; _opEndedCondition.notify_all();

我有一个类,通过它我可以异步提供一些服务(同样的调用也可以同步进行)。当被请求时,该类的对象(比如操作符)在不同的线程中启动该操作。其他对象可以注册到operator对象的通知,以便在操作结束时对该对象调用OperationEnded()方法。其他对象也可以通过调用操作符对象上的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);
}
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;不过,这样的解决方案很脆弱,而且在您的实现中,这可能只是将问题转移到另一段代码上

  • 最后,您可以实现所有这些的自定义组合


我们通过计算异步操作来解决这个问题

当构造一个新的操作符对象时,我们将其指针添加到引用计数表。 当这个对象开始一个异步操作时,我们增加引用计数 操作结束后,我们将减少引用计数

当对对象调用release时,如果引用计数为0,则删除它。如果大于0 我们将指针保持在一个soonToBeDeletables向量中。因此,当一个操作结束时,如果引用计数为0,并且如果执行该操作的操作符对象在sooToBeDeletables向量中,我们将删除操作符对象

当异步操作结束时,我们首先向条件变量发送信号,然后进行OperationEndd()调用。但反过来可能也会奏效

通过这种方法,数据竞争现在得到解决,删除是确定的。我们不需要一个后台工作线程,它将在一段时间后唤醒并进行删除。决定论是必需的,因为当几个对象因此被构造、使用(同步)和删除时,在一段时间内,几个对象将同时驻留在内存中,这在内存有限(移动)系统中是不需要的


经验教训:尽可能只提供一个通知机制。

只需要C++,或者我需要发布一些与C语言相关的代码?真正的问题在于资源管理,所以C不会太多相关。谢谢几个好主意,这些给了我一个很好的方向。我还编辑了这个问题,以提供有关API的更多信息。逐一评估您的报价。1-我无法控制所有的客户端代码(有这么多),因此这方面的任何解决方案都是不可能的。将API作为共享的ptr分发会很好,但是这里的任何更改都是不可接受的-我也不太喜欢用我的API分发boost版本。事实上,这本身是不够的,我们还应该自己保留shred_ptr以防止早期删除,并在某个点将其设置为null,这是最初的问题2-这是一个好的方向,但仍然会有一场竞赛。如果这个删除是通过一些同步手段而不是延迟来完成的,我可以接受这个解决方案。我认为这是最好的候选人。3-对象池会很好。但这仍然留下了一个问题,即我应该在没有争用/崩溃的情况下准确地删除对象。4-对象是可重用的。因此,这是不可接受的。对不起,我会将此信息添加到问题中。5-我无法修改客户端代码。OperationEnded()在客户端被覆盖。6-我认为结合一些线程安全措施的第二个选项会很好。对于解决方案2,您需要保留一个要删除的指针列表。当您向列表中添加POINER(和时间戳)(要删除)、从列表中读取指针和时间戳以及从列表中删除它们(如果给定的超时已过)时,需要同步此列表。延迟机制是一种避免删除冲突的方法(即,如果线程在调用
OperationEnded()
后(平均)1秒完成,则应在大约10秒后删除添加的指针。运算符对象是可重用的。其中一些对象可能会存活数月(该库也用于服务器机器).因此,拖延时间和希望避免冲突不适合这个库。