所以我正在阅读同步,并且遇到了监视器,但似乎无法理解它们是如何工作的。
我看到总体布局是以下格式的东西,我可以看作条件变量(我不确定这些是什么):
monitor {
// shared variables
procedure P1 (..) {..}
...
procedure P2 (..) {..}
initialisation code (..) {..}
}
然而,尽管我对此表示反对,但我还是看不到真正看到如何所描述的监视器一次只允许一个进程访问。
答案 0 :(得分:1)
我喜欢将监视器视为具有私有互斥锁的对象,并且每个过程都受该互斥锁保护。如下所示:
MyClass {
// private shared variables
...
mutex m;
// public procedures
Procedure P1(...) {
acquire(m);
...
release(m);
}
Procedure P2(...) {
acquire(m);
...
release(m);
}
initialisation code (...) { ... }
}
互斥锁保证一次只有一个线程/进程可以操作对象,因为每个公共过程都包含在互斥锁获取/释放中。
现在这些条件变量怎么样?嗯,通常你不需要它们。但有时你有一些条件,其中一个线程需要等待另一个线程,这就是条件变量的来源。
假设您正在实现并发队列对象。您将拥有push()
程序和pop()
程序。但是如果队列是空的,你该怎么办?
由于代码如下所示,单独的empty()和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()完成之前发生。)