pthread中的线程在一些迭代后停止工作

时间:2013-06-28 23:18:08

标签: c++ pthreads

我正在尝试编写多线程代码,但我遇到了一些问题。 在我的程序中,我有两种类型的线程,探险家(我有4或5)和主要(我有一个)。我希望所有探索者线程同时运行,当他们全部完成主线程开始它的工作。有一个循环,我一遍又一遍地做上面的事情。由于线程创建的开销,我决定让主要运行时探索器线程休眠,并在完成时唤醒它(当然反之亦然)。为了实现这一目标,我使用了障碍。以下是我的线程的伪代码:

主线程功能:

void* main(void* arg)
{
     while(true)
     {
         wait_for_barrier_1

         do_your_job

         reset_barrier_1
         wait_for_barrier_2
     }
}

资源管理器线程函数

void* explorers(void* arg)
{
     while(true)
     {

         do_your_job

         wait_for_barrier_1         

         if(thread_id == 0)
         {
             reset_barrier_2
         }             

         wait_for_barrier_2
     }
}

barrier_1用于在结束资源管理器之前阻止主要运行,而barrier_2用于在结束main之前阻止资源管理器。

我的问题是这段代码无法正常工作。一开始它工作正常,但经过两三次迭代后,一些探测器线程突然停止工作,因此整个程序将停止工作。

我无法弄清楚,特别是因为迭代次数没有规则。在某些运行中,它在第一次迭代后停止,在其他一些运行中它可以正常工作直到第5次或第6次。

顺便说一句,我使用的是Mac OSX。

2 个答案:

答案 0 :(得分:2)

在没有看到实际代码的情况下尽可能地回答,似乎主要是在资源管理器线程有reset_barrier_2之前通过wait_for_barrier_2

所以主循环回到wait_for_barrier_1,然后浏览器线程reset_barrier_2和wait_for_barrier_2。因为主要等待1,探险者等待2,没有人继续。

这样的事情:

Iteration 1:
main wait_for_barrier_1
                        explorers do_your_job
                        explorers wait_for_barrier_1
main do_your_job
                        explorers reset_barrier_2
                        explorers wait_for_barrier_2
main reset_barrier_1
main wait_for_barrier_2
main wait_for_barrier_1…

Iteration 2:
…main wait_for_barrier_1
                        explorers do_your_job
                        explorers wait_for_barrier_1
main do_your_job
main reset_barrier_1
main wait_for_barrier_2 (but it hasn't been reset yet! Runs right through!)
main wait_for_barrier_1
                        explorers reset_barrier_2
                        explorers wait_for_barrier_2

Deadlock!

我认为如果你在wait_for_barrier_1之前复位_barrier_2可能会有效,那么main在重置之前就无法通过wait_for_barrier_2。

答案 1 :(得分:0)

实际上问题是因为当你重置一个障碍时它失去了记忆并且忘记了之前有多么神奇的线程到达它。例如,探测器可能等待Barrier1,然后时间转到主要,主要通道Barrier1完成其工作并在资源管理器有机会通过之前重置它。所以在这种情况下,主要是等待Barrier2和资源管理器等待Barrier1(由主要重置)

为了解决这个问题,我为每个屏障使用了两个屏障变量,并在迭代中在它们之间切换。以下是我的伪代码。它完全正常。

主要功能:

void* main(void* arg)
{
     bool turn = false;

     while(true)
     {
         if(turn)
         {
             wait_for_barrier_1
         }
         else
         {
             wait_for_barrier_1_P
         }

         do_your_job

         if(turn)
         {
             reset_barrier_1_P
         }
         else
         {
             reset_barrier_1
         }

         if(turn)
         {
             wait_for_barrier_2
         }
         else
         {
             wait_for_barrier_2_P
         }

         turn = !turn ;
     }
}

资源管理器功能:

void* main(void* arg)
{
     bool turn = false;

     while(true)
     {
         do_your_job

         if(turn)
         {
             reset_barrier_2
         }
         else
         {
             reset_barrier_2_P
         }

         if(turn)
         {
             wait_for_barrier_1
         }
         else
         {
             wait_for_barrier_1_P
         }


         if(turn)
         {
             wait_for_barrier_2
         }
         else
         {
             wait_for_barrier_2_P
         }

         turn = !turn ;
     }
}

我知道它有点乱,但它运作正常。