2014-02-16 6 views
0

У меня есть следующий код синхронизации, и он, кажется, не ждет переменную условия по желанию. Цель состоит в том, чтобы порождать все потоки, а затем заставить всех начать работать одновременно.Правильное использование переменных условий

Преждевременно, как представляется, называется. Любые идеи почему?

chrono::milliseconds timeNThreadsLockFree(int n, int worksize) 
{ 
    boost::lockfree::stack<int> data(totalNumberOfWorkItems); 
    vector<thread> ts; 
    atomic<int> count; 
    condition_variable cv; 
    mutex mut2; 
    unique_lock<mutex> ul(mut2,defer_lock); 
    lock(ul,mut); 
    auto startSpawn = chrono::high_resolution_clock::now(); 
    for (int i = 0; i < n; i++) 
     ts.push_back(thread([&](){ 
     cv.wait(ul, [](){return true; }); 
     int q = 5; 
     for (int j = 0; j < worksize; j++){ 
      data.push(7); 
      else count++;} 
    })); 
    if (count != 0) { 
     cout << "premature" << endl; } 
    cv.notify_all(); 
    auto startWait = chrono::high_resolution_clock::now(); 
    for (auto&& t : ts) 
     t.join(); 
    auto endWait = chrono::high_resolution_clock::now(); 
    if (count != totalNumberOfWorkItems) 
     cout << "not done" << endl; 
    return chrono::duration_cast<chrono::milliseconds>(endWait - startWait); 
} 

ответ

0

Я думаю, что проблема со вторым аргументом в cv.wait вызова. cppreference говорит второй аргумент предиката вызывается, когда происходит ложное пробуждение, и что:

предикат возвращает ложь, если ожидание должно быть продолжено

Таким образом, чтобы убедиться, что замок на самом деле работает, вы, вероятно, следует сделать переменную как ready в основной функции, а затем использовать его в ожидании:

bool ready = false; 
... 
cv.wait(ul, [](){ return ready; }); 
... 
ready = true; 
cv.notify_all(); 

Кроме того, вы можете попробовать сделать отдельный std::unique_lock для каждого из потоков, вместо повторного использования одной из главной функции:

ts.push_back(thread([&]() { 
    std::unique_lock<std::mutex> ul2(mut2); 
    cv.wait(ul2, [](){ return ready; }); 

Затем, вам также необходимо, чтобы разблокировать старый замок в Основная функция:

ready = true; 
ul.ulock(); 
cv.notify_all(); 

Наконец, так как вы хотите, все потоки, чтобы работать в то же время, вы, вероятно, хотите, чтобы вручную разблокировать внутреннюю std::unique_lock сек, так что более чем один может работать :

ts.push_back(thread([&]() { 
    std::unique_lock<std::mutex> ul2(mut2); 
    cv.wait(ul2, [](){ return ready; }); 
    ul2.unlock(); 
+0

Если удалить лямбда я получаю «Блокировка проводится различными контексте» как утверждают неудачу в Visual Studio. То же самое дело, если я сделаю лямбда-ответ ложным. Идеи? – soandos

+0

Другая вещь, которую нужно отметить, это то, что я никогда не хочу, чтобы блокировка была необходима. Это делается в этом случае? – soandos

+0

@soandos Что произойдет, если вы попытаетесь создать отдельный 'std :: unique_lock' для каждого из потоков, с тем же мьютексом, а затем попробуйте дождаться этого? – Xymostech

0

Имея кучу блокировки/разблокировки/ожидания/уведомления по всему месту, вы часто понимаете, что используете неправильные инструменты. Используйте boost::barrier (или свернуть свой собственный, это просто реализовать):

boost::barrier bar(n+1); 
for (int i = 0; i < n; i++) 
    ts.push_back(thread([&](){ 
     bar.wait(); 
     // ... 
    })); 
// ... 
bar.wait(); // after this line all threads will be released from the barrier 
Смежные вопросы