Multithreading 监视器同步是如何工作的?
因此,我正在阅读有关同步的书籍,遇到了监视器,但似乎无法理解它们是如何工作的 我看到总体布局的格式如下所示,我可以将其视为条件变量(我不确定这些变量的作用):Multithreading 监视器同步是如何工作的?,multithreading,process,synchronization,semaphore,monitor,Multithreading,Process,Synchronization,Semaphore,Monitor,因此,我正在阅读有关同步的书籍,遇到了监视器,但似乎无法理解它们是如何工作的 我看到总体布局的格式如下所示,我可以将其视为条件变量(我不确定这些变量的作用): 然而,尽管我对此非常不满,但我看不出像上面描述的那样的监视器是如何一次只允许一个进程访问的。我喜欢将监视器视为一个具有专用互斥对象的对象,并且每个过程都受该互斥对象的保护。比如: MyClass { // private shared variables ... mutex m; // public procedures
然而,尽管我对此非常不满,但我看不出像上面描述的那样的监视器是如何一次只允许一个进程访问的。我喜欢将监视器视为一个具有专用互斥对象的对象,并且每个过程都受该互斥对象的保护。比如:
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!
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);
}
因此,您必须定义一个pop()过程,该过程在队列为空时返回一个特殊值,然后旋转等待队列变为非空。但是旋转等待的效率非常低
因此,您使用一个条件变量。条件变量有两种方法:wait()
和notify()
。Wait()自动放弃您持有的互斥锁,然后阻塞线程,直到其他线程调用notify()。所以像这样:
Thread A Thread B
if (not q.empty())
if (not q.empty())
then q.pop() // now q is empty!
then q.pop() // error!
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);
}
现在您有了一个数据结构/对象,其中一次只能有一个线程访问该对象,并且您可以处理不同线程之间的操作需要按特定顺序进行的情况(例如,在每个pop()完成之前,至少必须进行一次push()