2014-01-15 62 views
1

我目前正在使用boost 1.55.0,我不明白为什么这段代码不起作用。线程同步与boost :: condition_variable

以下代码是与我的程序具有相同问题的简化。小运行完成,但是当它们更大时,线程会一直等待。

boost::mutex m1; 
boost::mutex critical_sim; 

int total= 50000; 

class krig{ 

public: 

    float dokrig(int in,float *sim, bool *aux, boost::condition_variable *hEvent){ 

     float simnew=0; 

     boost::mutex::scoped_lock lk(m1); 

     if (in > 0) 
     { 
      while(!aux[in-1]){ 
       hEvent[in-1].wait(lk); 
      } 
      simnew=1+sim[in-1]; 

     } 

     return simnew; 
    }; 

}; 

void Simulnode(int itrd,float *sim, bool *aux, boost::condition_variable *hEvent){ 
    int j; 
    float simnew; 

    krig kriga; 

    for(j=itrd; j<total; j=j+2){ 

     if (fmod(1000.*j,total) == 0.0){ 
      printf (" .progress. %f%%\n",100.*(float)j/(float)total); 
     } 

     simnew= kriga.dokrig(j,sim, aux, hEvent); 

     critical_sim.lock(); 
     sim[j]=simnew; 
     critical_sim.unlock(); 

     aux[j]=true; 
     hEvent[j].notify_one(); 
    } 
} 


int main(int argc, char* argv[]) 
{ 
    int i; 
    float *sim = new float[total]; 

    bool *aux = new bool[total]; 

    for(i=0; i<total; ++i) 
     aux[i]=false; 

//boost::mutex m1; 

    boost::condition_variable *hEvent = new boost::condition_variable[total]; 

    boost::thread_group tgroup; 
    for(i=0; i<2; ++i) { 
     tgroup.add_thread(new boost::thread(Simulnode, i,sim, aux, hEvent)); 

    } 
    tgroup.join_all(); 

    return 0; 
} 

奇怪的是,我发现,如果我的地方就是dokrig()内内嵌在simulnode代码(),然后它似乎工作。这可能是锁的范围有问题吗?

有人可以告诉我我错了吗?提前致谢。

回答

0

的问题发生在这样的部分:

aux[j]=true; 
hEvent[j].notify_one(); 

第一行表示正在由hEvent条件变量监视的条件的改变。第二行向消费者宣称这一变化,即等待这种情况成为现实。

的问题是,这两个步骤发生没有同步与消费者,这可能会导致以下赛事:

  • 消费者检查的条件,这是目前假。这发生在由互斥锁m1保护的关键部分。
  • 发生线程切换。生产者将条件改变为真,并通知任何等待的消费者。
  • 线程切换回来。消费者恢复并呼叫等待。但是,他已经错过了最后一步发生的通知,所以他会永远等待。

理解传递给wait调用条件变量的互斥体的目的不是为了保护条件变量本身是很重要的,但条件,它监视(在这种情况下,是对aux的更改)。

为了避免数据竞争,写入aux和随后通知必须由同一个互斥体进行保护:

{ 
    boost::lock_guard<boost::mutex> lk(m1); 
    aux[j]=true; 
    hEvent[j].notify_one(); 
}