删除对象时清理引用对象的线程(在C ++中)

时间:2010-03-09 18:35:03

标签: c++ thread-safety destructor

我有一个对象(Client *客户端),它启动多个线程来处理各种任务(例如处理传入数据)。线程像这样启动:

// Start the thread that will process incoming messages and stuff them into the appropriate queues.
mReceiveMessageThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)receiveRtpMessageFunction, this, 0, 0);

这些线程都有对初始对象的引用,如下所示:

  // Thread initialization function for receiving RTP messages from a newly connected client.
  static int WINAPI receiveRtpMessageFunction(LPVOID lpClient)
  {
     LOG_METHOD("receiveRtpMessageFunction");
     Client * client = (Client *)lpClient;
     while(client ->isConnected())
     {
        if(client ->receiveMessage() == ERROR)
        {
           Log::log("receiveRtpMessageFunction Failed to receive message");
        }
     }

     return SUCCESS;
  }

定期删除Client对象(出于各种充分和充分的理由)。但是当发生这种情况时,仍然具有对(现在已删除的)对象的引用的处理线程在尝试访问该对象上的成员函数时会抛出一种或另一种异常。

所以我确信有一种标准的方法来处理这种情况,但我还是找不到干净的方法。我不想只是终止线程,因为这不允许清理资源。我无法在对象上设置属性,因为它正是对象上无法访问的属性。

关于处理这个问题的最佳方法的想法?

5 个答案:

答案 0 :(得分:2)

我会通过向您的对象引入引用计数来解决此问题。工作线程将保持引用,对象的创建者也是如此。您不是使用delete,而是从引用计数中减去,而删除最后一个引用的是实际调用delete的那个。

您可以使用现有的引用计数机制(shared_ptr等),或者您可以使用Win32 API InterlockedIncrement()InterlockedDecrement()或类似的推出自己的引用计数机制(可能引用计数是volatile DWORD从1开始......)。

唯一缺少的是当主线程释放其引用时,它应该向工作线程发出信号以丢弃它自己的引用。你能做到这一点的一种方法是event;您可以将工作线程的循环重写为WaitForMultipleObjects()的调用,并且当发出某个事件的信号时,您可以认为该工作线程应该清理并删除该引用。

答案 1 :(得分:1)

由于正在运行的线程,你没有太多的余地。

shared_ptr + weak_ptr的任何组合都不能保存您...您可以在对象有效时调用该方法,然后对其进行排序(仅使用shared_ptr)。

我唯一可以想象的是首先终止各种进程,然后销毁对象。通过这种方式,您可以确保每个进程正常终止,并在必要时清理自己的混乱(并且可能需要对象来执行此操作)。

这意味着您无法删除对象无法控制,因为您必须首先与使用它的人重新同步,并且您需要对同步部分进行一些事件处理(因为您基本上想要告诉线程停止,而不是无限期地等待它们。)

我将同步部分留给您,有很多选择(事件,标志等等),而且我们没有足够的数据。

您可以从析构函数本身处理实际的清理工作,也可以通过重载各种delete操作来处理,无论哪种操作都适合您。

答案 2 :(得分:0)

您需要有一些其他状态对象,线程可以检查以验证“客户端”是否仍然有效。

一个选项是将您的客户端引用封装在一些保持持久性的其他对象中,并从您的线程提供对该对象的引用。

答案 3 :(得分:0)

您可以在线程中为客户端使用带有代理对象的观察者模式。代理就像智能指针一样,转发对真实客户端的访问。当您创建它们时,它们会向客户端注册自己,以便它可以从析构函数中使它们无效。一旦它们失效,它们就会停止转发并返回错误。

答案 4 :(得分:0)

这可以通过将(boost)弱指针传递给线程来处理。