等待分离的线程在C ++中完成

时间:2009-11-15 02:49:31

标签: c++ multithreading pthreads corba

如何等待分离的线程在C ++中完成?

我不关心退出状态,我只是想知道线程是否已经完成。

我正在尝试围绕异步的第三方工具提供同步包装器。问题是涉及回调的奇怪的竞争状态崩溃。进展如下:

  1. 我致电第三方,并注册回拨
  2. 当第三方完成时,它使用回调通知我 - 在一个分离的线程中我无法真正控制。
  3. 我希望(1)中的线程等到(2)被调用。
  4. 我想将其包装在一个提供阻塞调用的机制中。到目前为止,我有:

    class Wait {
      public:
      void callback() {
        pthread_mutex_lock(&m_mutex);
        m_done = true;
        pthread_cond_broadcast(&m_cond);
        pthread_mutex_unlock(&m_mutex);
      }
    
      void wait() {
        pthread_mutex_lock(&m_mutex);
        while (!m_done) {
          pthread_cond_wait(&m_cond, &m_mutex);
        }
        pthread_mutex_unlock(&m_mutex);
      }
    
      private:
      pthread_mutex_t m_mutex;
      pthread_cond_t  m_cond;
      bool            m_done;
    };
    
    // elsewhere...
    Wait waiter;
    thirdparty_utility(&waiter);
    waiter.wait();
    

    据我所知,这应该有效,而且通常会有效,但有时它会崩溃。据我所知,我可以从核心文件中确定问题是:

    1. 当回调广播m_done结束时,等待线程唤醒
    2. 等待线程现在在这里完成,Wait被破坏。所有Wait的成员都被销毁,包括互斥和cond。
    3. 回调线程尝试从广播点继续,但现在正在使用已释放的内存,这会导致内存损坏。
    4. 当回调线程试图返回时(高于我糟糕的回调方法的级别),程序崩溃(通常使用SIGSEGV,但我已经看过几次SIGILL)。
    5. 我尝试了很多不同的机制来尝试解决这个问题,但没有一个能解决问题。我仍然偶尔会看到崩溃。

      编辑:更多详情:

      这是大规模多线程应用程序的一部分,因此创建静态Wait是不切实际的。

      我运行了一个测试,在堆上创建Wait,故意泄漏内存(即Wait对象永远不会被释放),这导致没有崩溃。所以我确定这是等待过早释放的问题。

      我在sleep(5)解锁后尝试使用wait进行测试,但也没有发生崩溃。我讨厌依靠这样的kludge。

      编辑:ThirdParty详细信息:

      我一开始并不认为这是相关的,但我想的越多,我认为这就是真正的问题:

      我提到的第三方内容,以及为什么我无法控制线程:这是使用CORBA。

      因此,CORBA可能会持续超过预期对我的对象的引用。

4 个答案:

答案 0 :(得分:3)

是的,我相信你所描述的正在发生(解除分配的竞争条件)。解决这个问题的一个简单方法是创建一个静态的Wait实例,一个不会被破坏的实例。只要您不需要同时拥有多个服务员,这将有效。

您还将永久使用该内存,它不会取消分配。但它看起来并不太糟糕。

主要问题是难以在线程之间协调线程通信结构的生命周期:当它可以安全销毁时,你总是需要至少一个剩余的通信结构来进行通信(至少在没有垃圾收集的语言中,比如C ++ )。

修改: 有关使用全局互斥锁引用计数的一些想法,请参阅注释。

答案 1 :(得分:0)

据我所知,如果线程已完成运行(即没有pthread_函数),则没有直接询问线程的可移植方式。你正在做什么正确的做法,至少就你有信号的条件而言。如果你看到崩溃,你肯定是因为Wait对象在创建它的线程退出时被释放(而不是某些其他微妙的锁定问题 - 太常见了) ,问题是您需要通过从执行通知的线程以外的线程进行管理来确保Wait 不被解除分配。将它放在全局内存中或动态分配它并与该线程共享。最简单的就是没有线程等待自己的内存等待,让线程做等待拥有它。

答案 2 :(得分:0)

您是否正确初始化并销毁互斥锁​​和条件var?

Wait::Wait()
{
    pthread_mutex_init(&m_mutex, NULL);
    pthread_cond_init(&m_cond, NULL);
    m_done = false;
}

Wait::~Wait()
{
    assert(m_done);
    pthread_mutex_destroy(&m_mutex);
    pthread_cond_destroy(&m_cond);
}

确保你没有过早地破坏Wait对象 - 如果它在一个线程中被破坏而另一个线程仍然需要它,你将获得一个可能导致段错误的竞争条件。我建议将它作为一个全局静态变量,它在程序初始化时构建(在main()之前)并在程序退出时被销毁。

答案 3 :(得分:0)

如果您的假设是正确的,那么第三方模块似乎是错误的,您需要提出某种方法来使您的应用程序正常工作。

静态Wait不可行。如果Wait池(它甚至可能按需增长)怎么样?您是使用线程池运行的应用程序吗? 虽然第三方模块仍然在使用它时,仍然有可能重复使用相同的Wait。但是你可以通过适当排队游泳池中空缺的等待来最小化这种机会。

免责声明:我绝不是线程安全方面的专家,所以请将此帖作为外行人的建议。