2024年4月2日发(作者:)
使用Win32提供的临界区可以方便的实现线程锁:
// 全局:
CRITICAL_SECTION cs;
InitializeCriticalSection( & cs);
// 线程1:
EnterCriticalSection( & cs);
int a = s.a;
int b = s.b;
LeaveCriticalSection( & cs);
// 线程2:
EnterCriticalSection( & cs);
s.a ++ ;
s.b -- ;
LeaveCriticalSection( & cs);
// 最后:
DeleteCriticalSection( & cs);
代码中的临界区变量(cs)就可以看作是变量s的锁,当函数
EnterCriticalSection返回时,当前线程就获得了这把锁,之后就是对变量的
访问了。访问完成后,调用LeaveCriticalSection表示释放这把锁,允许其他
线程继续使用它。
如果每当需要对一个变量进行加锁时都需要做这些操作,显得有些麻烦,而
且变量cs与s只有逻辑上的锁关系,在语法上没有什么联系,这对于锁的管理
带来了不小的麻烦。程序员总是最懒的,可以想出各种偷懒的办法来解决问题,
例如让被锁的变量与加锁的变量形成物理上的联系,使得锁变量成为被锁变量不
可分割的一部分,这听起来是个好主意。
首先想到的是把锁封闭在一个类里,让类的构造函数和析构函数来管理对锁
的初始化和锁毁动作,我们称这个锁为“实例锁”:
class InstanceLockBase
... {
CRITICAL_SECTION cs;
protected :
InstanceLockBase() ... { InitialCriticalSection( & cs); }
~ InstanceLockBase() ... { DeleteCriticalSection( & cs); }
} ;
如果熟悉C++,看到这里一定知道后面我要干什么了,对了,就是继承,因
为我把构造函数和析构函数都声明为保护的(protected),这样唯一的作用就
是在子类里使用它。让我们的被保护数据从这个类继承,那么它们不就不可分割
了吗:
struct MyStruct: public InstanceLockBase
... { „ } ;
什么?结构体还能从类继承?当然,C++中结构体和类除了成员的默认访问
控制不同外没有什么不一样,class能做的struct也能做。此外,也许你还会
问,如果被锁的是个简单类型,不能继承怎么办,那么要么用一个类对这个简单
类型进行封装(记得Java里有int和Integer吗),要么只好手工管理它们的
联系了。如果被锁类已经有了基类呢?没关系,C++是允许多继承的,多一个基
类也没什么。
现在我们的数据里面已经包含一把锁了,之后就是要添加加锁和解锁的动
作,把它们作为InstanceLockBase类的成员函数再合适不过了:
class InstanceLockBase
... {
CRITICAL_SECTION cs;
void Lock() ... { EnterCriticalSection( & cs); }
void Unlock() ... { LeaveCriticalSection( & cs); }
„
} ;
看到这里可能会发现,我把Lock和Unlock函数都声明为私有了,那么如何
访问这两个函数呢?是的,我们总是需要有一个地方来调用这两个函数以实现加
锁和解锁的,而且它们总应该成对出现,但C++语法本身没能限制我们必须成对
的调用两个函数,如果加完锁忘了解,那后果是严重的。这里有一个例外,就是
C++对于构造函数和析构函数的调用是自动成对的,对了,那就把对Lock和
Unlock的调用专门写在一个类的构造函数和析构函数中:
class InstanceLock
... {
InstanceLockBase * _pObj;
public :
InstanceLock(InstanceLockBase * pObj)
... {
_pObj = pObj; // 这里会保存一份指向s的指针,用于解锁
if (NULL != _pObj)
_pObj -> Lock(); // 这里加锁
}
~ InstanceLock()


发布评论