Giriş
Şu satırı dahil ederiz.
Constructor
Şöyle yaparız.
Nesne üzerinde beklemekte olan tüm thread'leri uyandıdır. Şöyle yaparız.
Nesne üzerinde beklemekte olan bir thread'i uyandırır. Şöyle yaparız
Şu satırı dahil ederiz.
#include <condition_variable>
Condition nesnesi unique_lock ile kullanılır. Başka bir lock tipi ile kullanıldığını görmedim.Constructor
Şöyle yaparız.
condition_variable cv;
notify_all metoduNesne üzerinde beklemekte olan tüm thread'leri uyandıdır. Şöyle yaparız.
cv.notify_all();
notify_one metoduNesne üzerinde beklemekte olan bir thread'i uyandırır. Şöyle yaparız
cv.notify_one (); // notify one waiting thread
Spurious (Sahte/Yalancı) wakeup
wait(), wait_for() ve türevleri, condition_variable notfiy() veya notify_all() çağrısı almadan da bir sonuç döndürebilirler. Buna Spurious wakeup deniliyor. Dolayısıyla wait() ve türevlerinden döndükten sonra istenilen koşulu kontrol etmek gerekiyor.
Örnek - Kontrol Etmezsek
Elimizde şöyle bir kod olsun. Burada beklenti thread'in sonsuza kadar dönmesi, ancak öyle olmuyor. Thread, Spurious wakeup ile uyandırılıyor ve çağrı sonucu std::cv_status::timeout yerine std::cv_status::no_timeout geliyor. Bu durumda da thread döngüden çıkıyor.
std::condition_variable cv;
std::mutex mtx;
bool called = false;
void printThread()
{
std::unique_lock<std::mutex> lck(mtx);
while (std::cv_status::timeout == cv.wait_for(lck, std::chrono::seconds(1)))
{
std::cout << "*";
}
std::cout << "thread exits" << std::endl;
}
int main()
{
std::thread th(printThread);
th.join();
std::cout << "program exits" << std::endl;
}
wait metodu - while döngüsü
Metoda girişte mutex'i bırakır çıkışta ise kilitler. Spurious wakeup'a dikkat etmek gerekir. Bu yüzden while döngüsü içinde kullanmak gerekir. Örnek
Şöyle yaparız
Açıklaması şöyle. spurious wakeup'a dikkat etmek gerekir. Bu yüzden lamda ile kullanılıyor.
std::unique_lock <std::mutex> locker (mutex);
while (queue.empty())
{
cond_.wait(mlock);
}
...
wait metodu - lambdaAçıklaması şöyle. spurious wakeup'a dikkat etmek gerekir. Bu yüzden lamda ile kullanılıyor.
Metoda girişte mutex'i bırakır çıkışta ise kilitler. Çıkış koşulu lambda'nın true dönmesidir. Bu metod while döngüsü kullanmamızı engeller.Atomically releases lock, blocks the current executing thread, and adds it to the list of threads waiting on *this. The thread will be unblocked when notify_all() or notify_one() is executed. It may also be unblocked spuriously. When unblocked, regardless of the reason, lock is reacquired and wait exits. If this function exits via exception, lock is also reacquired. (until C++14)
Örnek
Şöyle yaparız.
wait_for() metodu std::this_thread::sleep_for ile aynı gibi görünüyor. Ancak arada bir fark var. condition_variable süre bitmeden önce de uyandırılabilir. Yani spurious wakeup'a dikkat etmek gerekir. Bu yüzden lamda ile kullanılıyor.
Örnek
Şöyle yaparız.
Şöyle yaparız.
While döngüsü içinde kullanmamızı engeller. spurious wakeup'a dikkat etmek gerekir. Bu yüzden predicate ile kullanılıyor.
Örnek
Şöyle yaparız.
std::mutex m;
std::condition_variable cv;
std::unique_lock<std::mutex> locker (m);
cv.wait(locker,[](){return ...;});
Örnek
Elimizde bir veri yapısı olsun ve istenilen sayıda eleman oluncaya kadar beklemek isteyelim. Şöyle yaparız.void Foo::extract (const unsigned int n)
{
// Wait until the buffer is not empty
std::unique_lock<mutex> locker (m);
cv.wait (locker, [this, n](){
return (int)(v.size() - n) >= 0;
});
...
//Consume. Not full any more
cv.notify_one();
}
wait_for metodu - timeout + lambdawait_for() metodu std::this_thread::sleep_for ile aynı gibi görünüyor. Ancak arada bir fark var. condition_variable süre bitmeden önce de uyandırılabilir. Yani spurious wakeup'a dikkat etmek gerekir. Bu yüzden lamda ile kullanılıyor.
Örnek
Şöyle yaparız.
const std::chrono::milliseconds timeout (3000 );
if(cv.wait_for (locker, timeout, [] {return ...; }) ) {...}
ÖrnekŞöyle yaparız.
// Somewhere else, e.g. in a header:
std::mutex mutex;
bool condition_to_be_met{false};
std::condition_variable cv;
// In your timer:
// ...
std::unique_lock<std::mutex> lock{mutex};
if(!cv.wait_for(lock, std::chrono::milliseconds{timeout_ms},
[this]{return condition_to_be_met;}))
std::cout << "timed out!" << std::endl;
Tetiklemek için şöyle yaparız.{
std::lock_guard<std::mutex> lock{mutex}; // Same instance as above!
condition_to_be_met = true;
}
cv.notify_one();
wait_for metodu - timeout + predicateWhile döngüsü içinde kullanmamızı engeller. spurious wakeup'a dikkat etmek gerekir. Bu yüzden predicate ile kullanılıyor.
Örnek
Şöyle yaparız.
const std::chrono::milliseconds timeout (3000 );
if(cv.wait_for (locker, timeout, myPredicate
) {...}
predicate şöyledir.bool myPredicate(){
return ...;
}
wait_until metodu
Şöyle yaparız.
Diğer Notlar
Barrier Örneği
auto delay = ...;
std::unique_lock<std::mutex> lock (m);
cv.wait_until (lock,delay,[] { return ...; });
Diğer Notlar
Barrier Örneği
class Barrier
{
std::mutex& lock;
int count;
std::condition_variable threadBarrier;
public:
Barrier(std::mutex& m, int count) : lock(m), count(count) {}
void checkin()
{
std::unique_lock<std::mutex> locker(lock);
--count;
if (count > 0)
{
threadBarrier.wait(locker, [&count, this](){
return count <= 0;
});
}
else
{
threadBarrier.notify_all();
}
}
};
Hiç yorum yok:
Yorum Gönder