新的问题
保护原则的正确性已经验证,但是在实现时,我们发现了两个新问题。
第一个是刚才的实现中,似乎打破了我们以前说的对称原则,仔细看代码会发现在Modify 函数中,mutex_lock 被调用了一次,而mutex_unlock 却被调用了2次。这个问题虽然是个小问题,但是对于完美主义的我而言,却是个大问题。当然,在培训的实践中,也确实发现部分学员很容易忘记第一个mutex_unlock 的调用,这当然会产生程序的bug。好的程序总是优美的,并且总是简明的,可是,在Modify 函数中,因为保护原则,我们看不到代码的优美和简明。
第二个问题是在一个大的多线程程序中,如果要对每个共享数据都进行保护,那也许我们需要的互斥量有点过于多了,以至于程序可读性会变得很差,mutex_lock、mutex_unlock 到处都是。很多程序员正是因为实现上的繁琐,所以才会在代码中打破保护原则,而一旦保护原则被打破,则程序的 bug 也将随之而来,这真是很难办的事情。
CGuard 类
CGuard类是专门为解决上述第一个问题而设计和实现的类,并且,这个类的使用也非常方便。下面看一下使用 CGuard 类改造后的程序。
#include <stdio.h>
#include <windows.h>
#include "..\..\port\port.h"
#include "..\..\port\Mutex.h"
#include "..\..\port\Guard.h"
static DWORD WINAPI MyThread( LPVOIDlpParam );
static CMutex mutex;
static int num = 20;
static int Modify(int index);
int main(int argc, char *argv[])
{
HANDLEhThread[4];
inti;
for( i=0; i<4; i++ )
{
hThread[i]= CreateThread(NULL, 0, MyThread, (LPVOID)i, 0, 0);
}
for( i=0; i<4; i++ )
{
WaitForSingleObject(hThread[i],INFINITE);
}
return0;
}
DWORD WINAPI MyThread( LPVOID lpParam )
{
intindex = (int)lpParam;
printf("id:%d\n", index);
while(1)
{
if(Modify(index)!=0)
break;
}
return0;
}
static int Modify(int index)
{
CGuardguard(mutex);
if(num>0)
{
printf("[id:%d]num = %d\n", index, num);
Sleep(100);
printf("[id:%d]num = %d\n", index, num--);
}else
{
return-1;
}
return0;
}