我编写了以下程序,用于使用增强条件变量来交替增加和加倍计数器(增量优先)。任何人都能告诉我这是否正确使用了增强条件变量。它工作正常。我不明白在wait函数调用中使用lock。 condition.wait(lock)是什么意思?例如,在此程序中增量和乘法使用两个范围锁是什么。我该如何避免它们?
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/condition_variable.hpp>
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int counter=0;
boost::mutex m1,m2;
bool incremented=false,multiplied=false;
boost::condition_variable c1,c2;
void Increment()
{
{
boost::mutex::scoped_lock lk(m1);
counter++;
incremented = true;
c1.notify_one();
while(!multiplied)
c2.wait(lk);
multiplied=false;
}
}
void Multiply()
{
{
boost::mutex::scoped_lock lk(m2);
while(!incremented)
c1.wait(lk);
incremented = false;
counter = counter*2 ;
multiplied = true;
c2.notify_one();
}
}
void IncrementNtimes(int n){
for(int i=0;i<n;i++){
Increment();
}
}
void MultiplyNtimes(int n){
for(int i=0;i<n;i++){
Multiply();
}
}
int main(int argc, char* argv[])
{
srand ( time(NULL) );
boost::thread thrd1(boost::bind(&IncrementNtimes,20));
boost::thread thrd2(boost::bind(&MultiplyNtimes,20));
thrd1.join();
thrd2.join();
cout<<"Main counter is:"<<counter<<endl;
return 0;
}
答案 0 :(得分:18)
不,这不正确。你几乎就在那里,但最大的问题是Multiply和Increment函数应该使用相同的互斥锁。
互斥锁是一个提供MUTual EXclusion的对象。换句话说,互斥锁的要点是防止两个线程同时触及同一个变量并导致不可预测的结果。互斥体有点像一个线程,一次持有一个线程,使其具有访问某个变量(或一组变量)的“权利”。在这种情况下,您要保护的变量是counter
。必须有一个且仅有一个互斥锁控制访问counter
的权限。在您的情况下,每个线程将拥有自己的令牌,它认为它有权访问计数器,因此会出现不可预测的行为。
通过锁定它来“保持”互斥锁。这就是锁的重点,这就是为什么你不能“避免”它们。范围锁的整个点是,假设您只有一个互斥锁m
,当其中一个线程持有m
上的锁时,另一个线程保证也不会持有锁m
。如果您已正确编码,则m
上的锁定应该是访问counter
的先决条件,因此counter
的值应该是可预测的。
现在,关于wait()
。对wait()
的调用意味着“我放弃对此互斥锁的锁定,直到其他人发出这种情况为止,然后我又想要它”。同时,线程停止。因此,假设您只有一个互斥m
且条件c
,而lk
是对m
的锁定,则行c.wait(lk)
表示该线程将提供在lk
上锁定m
然后暂停执行,直到其他线程调用c.notify_one()
(或c.notify_all()
)。当等待线程从呼叫返回wait()
时,它将自动重新获得lk
上的锁m
,因此可以再次访问counter
。
最后,这些提升锁是“范围”锁。这意味着它们会在销毁时自动释放(当它们超出范围时)。因此,在这种情况下,每个函数都会保持锁定直到它退出,除非它已经放弃锁定等待并暂停执行等待信号。
答案 1 :(得分:4)
锁定与条件变量相关联,因为条件变量是无状态的 - 如果线程A在没有服务器时发出信号,而线程B则进入等待状态,则B将不会被唤醒。因此,必须存在与条件变量相关联的状态(在这种情况下,递增和相乘。)锁保护跨多个线程访问的此状态。当你将锁传递给wait()时,wait将自动释放锁并等待条件变量,并在等待返回时重新获取锁。这意味着没有窗口,条件变量后面的状态可能已经改变并且等待发生。
例如,如果条件变量没有绑定到锁:
// In thread A
while(!incremented)
// Context switch to Thread B:
incremented = true;
// Context switch to Thread A:)
c1.wait(); // Whoops, waiting for a condition that already happened.
答案 2 :(得分:2)
条件变量必须始终与锁相关联。要意识到的一点是你必须持有锁来调用wait(),但是一旦进入wait(),锁就会被释放。当你发出信号时,你也必须握住锁,最后等待不会返回(即使在信号之后),直到信号器解锁。