2014-01-15 3 views
1

В настоящее время я использую boost 1.55.0, и я не могу понять, почему этот код не работает.Thread syncronization with 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.
  • Переключатель потока. Производитель изменяет условие на true и уведомляет всех ожидающих потребителей.
  • Резьбовые соединения. Потребитель возобновляет и вызывает ожидание. Однако он уже пропустил уведомление, которое произошло на последнем этапе, поэтому он будет ждать всегда.

Важно понимать, что цель мьютекса, который передается в wait вызова переменных условий не для защиты самого условия переменного, но состояние , что он контролирует (в данном случае это изменение на aux).

Чтобы избежать гонки данных, запись aux и последующее уведомлять должны быть защищены той же мьютекс:

{ 
    boost::lock_guard<boost::mutex> lk(m1); 
    aux[j]=true; 
    hEvent[j].notify_one(); 
} 
Смежные вопросы