2012-11-27 45 views
3

我目前正在编写一个多线程程序,根据某些情况有时可能会创建一个线程。如果创建该线程,它需要独立于所有其他线程运行,并且我无法阻止任何其他线程等待它加入。产生的线程运行的时间长短不一;有时可能需要几个小时。多线程程序线程连接问题

我已经试过产卵的线程,并在类的析构函数中工作正常,但如果产生的线程内的代码完成很长时间才析构函数被调用(这将是约99%的时间)我想线程自己释放它的所有资源等。

我看着使用detach为此,但你不能重新加入一个分离的线程和在此线程完成之前调用析构函数的机会那么产生的线程将不会完成并且可能具有灾难性的后果。

是否有任何可能的解决方案确保线程在类被破坏之前完成,并且一旦线程完成其工作就允许线程加入?

我使用boost/C++ 11进行线程化。任何帮助都将不胜感激。

感谢

+0

编辑。任何帮助都将是非常感谢 –

+1

你可能想看看['std :: notify_all_at_thread_exit'](http://en.cppreference.com/w/cpp/thread/notify_all_at_thread_exit)。 –

+0

@JoachimPileborg谢谢你将会看到它 –

回答

4

线程可能会分离自己,释放其资源。如果析构函数看到线程可以连接,即仍在运行,那么让它加入。如果线程到达末端,则自行分离。可能的竞态条件: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(); 
    } 
}; 
+0

谢谢,看起来它可能是一个很好的解决方案。将测试出来,看看它是如何发展。 –

+0

似乎从最初的测试中运行良好。互斥选项是首选的感谢 –

1

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

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

+0

使用函数的第二个选项可能有效。我试试看,谢谢 –