2013-06-03 8 views
22

Başka bir iş parçacığı işlenmeyi tamamlayana kadar bir iş parçacığı durdurmak için koşullu bir değişken kullanıyorum görev sırası (uzun hikaye). Yani, bir iş parçacığı üzerinde ben kilitlemek ve bekle şu şekildedir:Bir iş parçacığının işlemeyi tamamlamasını beklemek için bir destek koşulu değişkenini nasıl kullanırım?

boost::mutex::scoped_lock lock(m_mutex); 
m_condition.wait(lock); 

diğer iplik 's görevleri tamamlandıktan sonra, bekleyen iş parçacığı işaret:

boost::mutex::scoped_lock lock(m_parent.m_mutex); 
m_parent.m_condition.notify_one(); 

görüyorum sorun bekleyen olmasıdır Aşağıdaki yönergeleri bir kesme noktası ayarlamadık sürece iş parçacığı beklemez (Ben xcode, fyi kullanıyorum). Evet, bu garip görünüyor. Bunun neden olabileceğini bilen var mı? Koşul değişkenini yanlış mı kullanıyorum?

+0

kodu ... biraz kafa karıştırıcı ilk 'ikinci' m_parent.m_mutex' aynı örneği m_mutex' mı? –

cevap

42

Evet, koşul değişkenini yanlış kullanıyorsunuz. "Koşul değişkenleri" gerçekten sadece sinyal mekanizmasıdır. Ayrıca bir koşulu test etmelisiniz. Durumunuzda, notify_one() çağıran iş parçacığının, wait() numaralı çağrıları başlatan iş parçacığı başlamadan gerçekten tamamlanmış olması durumu olabilir. (Ya da en azından wait() çağrısından önce notify_one() çağrısı gerçekleşir.) Buna "cevapsız uyandırma" denir.

çözüm aslında umurumda koşulu içeren bir değişken sahip olmaktır: diğer iplik o zaman bile bekleyen başlamadan önce worker_is_done==true sadece düşeceğiz Eğer

bool worker_is_done=false; 

boost::mutex::scoped_lock lock(m_mutex); 
while (!worker_is_done) m_condition.wait(lock); 

ve

boost::mutex::scoped_lock lock(m_mutex); 
worker_is_done = true; 
m_condition.notify_one(); 

Süre boyunca hiçbir zaman wait() numaralı telefonu aramadan.

Bu desen o kadar yaygındır ki, condition_variable.wait()'unuzu sarmak için bir while döngüsüne sahip değilseniz, her zaman bir hata vardır. Aslında, ne zaman C++ 11 boost benzer bir şey kabul :: Bir yüklem lambda ifadesi alır) onlar bekle (yeni bir tür eklendi condtion_variable (aslında bu sizin için while döngü yapar):

std::condition_variable cv; 
std::mutex m; 
bool worker_is_done=false; 


std::unique_lock<std::mutex> lk(m); 
cv.wait(lk, []{return worker_is_done;}); 
+0

Boost :: mutex :: scoped_lock lock (m_mutex); 'bekleyen iş parçacığı için ne gerekiyor? notify_one(), args almaz. – ItsmeJulian

+0

"worker_is_done" için bir atomik yazı sağlamak için var. Alternatif, türü yalnızca "bool" yerine "atomik " olarak bildirmektir. –

+0

@DavidStone Kod, 1 bayt atamasının atomik olduğu bir işlemci üzerinde çalışıyorsa, ör. x86? Bu durumda kilidine ihtiyacımız olmayacak, değil mi? – user3286661

2

Tartışmaya dayanarak destek koşulunun nasıl kullanılacağını gösteren bir örnek uygulamıştım.

#include <iostream> 

#include <boost/asio.hpp> 
#include <boost/thread/mutex.hpp> 
#include <boost/thread/thread.hpp> 

boost::mutex io_mutex; 
bool worker_is_done = false; 
boost::condition_variable condition; 

void workFunction() 
{ 
    std::cout << "Waiting a little..." << std::endl; 
    boost::this_thread::sleep(boost::posix_time::seconds(1)); 
    worker_is_done = true; 
    std::cout << "Notifying condition..." << std::endl; 
    condition.notify_one(); 
    std::cout << "Waiting a little more..." << std::endl; 
    boost::this_thread::sleep(boost::posix_time::seconds(1)); 
} 

int main() 
{ 
    boost::mutex::scoped_lock lock(io_mutex); 
    boost::thread workThread(&workFunction); 

    while (!worker_is_done) condition.wait(lock); 
    std::cout << "Condition notified." << std::endl; 
    workThread.join(); 
    std::cout << "Thread finished." << std::endl; 

    return 0; 
} 

Boost condition variable example

+3

İşçi kilidini, worker_is_done değerini true değerine ayarlamadan önce mi yapmalısınız? –

+0

Sanırım yapmalı. –

İlgili konular