【问题标题】:Multithreaded program thread join issues多线程程序线程连接问题
【发布时间】:2012-11-14 21:49:53
【问题描述】:

我目前正在编写一个多线程程序,有时可能会根据某些情况创建线程。如果创建了这个线程,它需要独立于所有其他线程运行,我不能阻止任何其他线程等待它加入。生成的线程运行的时间长度各不相同;有时可能需要几个小时。

我已经尝试生成线程并在类的析构函数中加入一个工作正常的连接,但是如果生成的线程中的代码在调用析构函数之前完成了很长时间(大约 99% 的时间) ) 我希望线程杀死自己释放所有资源等。

我研究过为此使用 detach,但是您不能重新加入一个分离的线程,并且如果在该线程完成之前调用析构函数,那么生成的线程将不会完成并可能产生灾难性的后果。

是否有任何可能的解决方案可以确保线程在类被破坏之前完成,并允许它在线程完成工作后立即加入?

我正在使用 boost/c++11 进行线程处理。任何帮助都将不胜感激。

谢谢

【问题讨论】:

  • 已编辑。任何帮助都会非常感谢
  • 您可能想查看std::notify_all_at_thread_exit
  • @JoachimPileborg 谢谢会调查它
  • 为什么你认为一个已经结束的线程并没有销毁它所有的资源?
  • @StephaneRolland 我需要确保当这个线程启动时它完全完成。如果它在完成中途停止,将对我的整个项目产生很多不利影响。我并没有说明完成的线程不会破坏资源。

标签: c++ multithreading boost c++11


【解决方案1】:

线程可能会自行分离,释放其资源。如果析构函数看到线程是可加入的,即仍在运行,让它加入。如果线程到达终点,则自分离。可能的竞争条件:is_joinable() 在析构函数中返回 true - 线程自行分离 - 析构函数加入并惨遭失败。所以使用互斥锁来保护线程的死亡:

struct ThreadContainer
{
   std::mutex threadEndMutex;
   std::thread theThread;

   ThreadContainer()
     : theThread([=]()
       {
         /* do stuff */

         // if the mutex is locked, the destructor is just
         // about to join, so we let him.
         if (threadEndMutex.try_lock())
           theThread.detach();
       })
   {}

   ~ThreadContainer()
   {
     // if the mutex is locked, the thread is just about 
     // to detach itself, so no need to join.
     // if we got the mutex but the thread is not joinable, 
     // it has detached itself already.
     if (threadEndMutex.try_lock() && theThread.is_joinable())
       theThread.join();
   }
};

PS: 您甚至可能不需要调用 is_joinable,因为如果线程自行分离,它永远不会解锁互斥锁并且 try_lock 会失败。

PPS: 您可以使用 std::atomic_flag 来代替互斥锁:

struct ThreadContainer
{
   std::atmoic_flag threadEnded;
   std::thread theThread;

   ThreadContainer()
     : threadEnded(ATOMIC_FLAG_INIT)
     , theThread([=]()
       {
         /* do stuff */

         if (!threadEnded.test_and_set())
           theThread.detach();
       })
   {}

   ~ThreadContainer()
   {
     if (!threadEnded.test_and_set())
       theThread.join();
   }
};

【讨论】:

  • 谢谢,看来这可能是一个很好的解决方案。将对其进行测试,看看效果如何。
  • 在最初的测试中似乎运行良好。首选 mutex 选项,谢谢
【解决方案2】:

您可以在“独立”线程算法中定义暂停/步骤,并在每个步骤中查看一个全局变量,帮助您决定取消计算并自动销毁,或继续线程中的计算。

如果全局变量不够用,即如果需要更精确的粒度,您应该为您的线程函数定义一个仿函数对象,这个仿函数有一个方法 kill()。在将仿函数作为线程启动后,您可以保留对仿函数的引用。当您调用 MyThreadFunctor::kill() 时,它会设置一个布尔字段,并且在仿函数线程函数本身的计算的每个步骤中都会检查该字段。

【讨论】:

  • 使用仿函数的第二个选项可能会起作用。我试试看,谢谢
猜你喜欢
  • 2023-03-26
  • 1970-01-01
  • 2013-03-06
  • 2011-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
相关资源
最近更新 更多