我喜歡將監視器想象成具有私有互斥鎖的對象,並且每個過程都受該互斥鎖的保護。因此,像:
MyClass {
// private shared variables
...
mutex m;
// public procedures
Procedure P1(...) {
acquire(m);
...
release(m);
}
Procedure P2(...) {
acquire(m);
...
release(m);
}
initialisation code (...) { ... }
}
的互斥體,保證在某時刻只有一個線程/進程可以被操縱的對象,因爲每一個公共程序是包裹着互斥鎖獲取/釋放。
那麼這些條件變量呢?那麼,你通常不需要它們。但是有時你有一些條件,一個線程需要等待另一個線程,這就是條件變量進入的地方。
假設例如您正在實現併發隊列對象。您將有一個push()
程序和一個pop()
程序。但是如果隊列是空的,你應該怎麼做?
它不會工作,有獨立的空()和pop()方法,因爲這樣的代碼,:
Thread A Thread B
if (not q.empty())
if (not q.empty())
then q.pop() // now q is empty!
then q.pop() // error!
所以,你必須定義它返回一個特殊值的pop()方法步驟當隊列爲空時,然後旋轉等待隊列變爲非空。但旋轉等待效率非常低。
因此,您可以使用條件變量。條件變量有兩種方法:wait()
和notify()
。 Wait()以原子方式放棄所持有的互斥鎖,然後阻塞該線程,直到某些其他線程調用notify()。所以像這樣的:
condition_variable cv;
Procedure int pop() {
acquire(m);
while (q.empty()) {
wait(cv, m) // atomically release m and wait for a notify() on cv.
// when wait() returns it automatically reacquires mutex m for us.
}
rval = q.pop();
release(m);
return rval;
}
Procedure push(int x) {
acquire(m);
q.push(x);
notify(cv); // wake up everyone waiting on cv
release(m);
}
現在你有一個數據結構/對象,其中只有一個線程可以在同一時間內訪問對象,並在不同的線程之間的操作都需要在一個發生,你可以照顧的情況下,特定的順序(如至少一個push()必須在每個pop()完成之前發生。)