有过多线程开发经历的人,对于“互斥对象,临界区,事件,信号量”这四个对象肯定不会陌生。就我自己而言,它们真是"让我欢喜让我忧"。"让我欢喜" 因为利用它们往往能解决掉非常棘手的问题,例如经典的"生产者-消费者"问题,"让我忧"因为,我经常把它们搞混淆,用的时候不知道到底该用哪个好,比如我觉互斥对象和信号量这两者很相似,在解决"生产者-消费者"问题时,为了实现线程同步很多例子中都用了信号量,为什么不用互斥对象实现呢?我试图用互斥对象来做了一下,结果失败了。
今天我决定解决掉这个问题。仔细阅读了MSDN上关于"Mutex,CriticalSection,Envent,Semaphore"的相关函数的介绍,特被是Create* 函数的介绍后,我终于弄清楚了这个问题;
首先我给它们分成两组:
Mutex和CriticalSection是用于实现数据的互斥的访问;
Envent和Semaphore不但可以用于实现互斥,而且能够能与实现线程同步;
究竟是什么原因导致Mutex不能实现线程同步呢?
答案:Mutex在没有被任何线程所拥有时是有信号的,这时任何线程可以使用Wait functions去获取该对象的所有权。当Mutex被某个线程拥有后就处于没信号状态,并且只有当该线程使用ReleaseMutex释放该互斥对象时,它才能被其它线程获得。
在一个线程中试图释放另个线程所拥有的Mutex是不会成功的,Mutex只能被所有者线程所释放。(这是主要原因)
我们看看"生产者-消费者"问题:
全局共享变量g_share相当于一个货架(一个只能摆放一件产品的货架)。初始情况下货架为空。只有当货架不为空时才允许消费者(DecProc)从货架上取走商品(减一操所),只有当货架上为空时才允许生产者(AddProc)往货架上放商品。生产者与消费者必须实现同步。否则就会出现不合逻辑的现象。
从上图我们可以看出在AddProc中需要对g_decSemaphore进行释放操作,在DecProc中需要对g_addSemaphore进行释放操作。但是由于Mutex的释放操作只能由所有者线程进程,在一个线程中释放其它线程所拥有的Mutex是不会成功的。正是这个原因,导致Mutex不能用于实现线程同步。而Envent,Semaphore和都可以在其它线程中设置其信号状态,所以他们能够用于实现线程同步。
使用信号量Semaphore进行线程同步的例子很多,下面我给出一个用Envent实现同步的例子:
#include <windows.h>
int g_share=0;
HANDLE hmutex;
HANDLE g_addEvent;
HANDLE g_decEvent;
DWORD WINAPI AddProc(
LPVOID lpParameter // thread data
);
DWORD WINAPI DecProc(
LPVOID lpParameter // thread data
);
int main()
{
SECURITY_ATTRIBUTES sa;
DWORD dwStackSize=0;
LPVOID lpParameter=NULL;
DWORD dwCreationFlags=0;
DWORD addThreadId;
DWORD decThreadId;
HANDLE addhandle;
HANDLE dechandle;
memset((BYTE *)&sa,0,sizeof(SECURITY_ATTRIBUTES));
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
//创建互斥对象实现g_share的互斥访问
hmutex=CreateMutex(&sa,FALSE,NULL);
//创建事件实现进程同步
g_addEvent=CreateEvent(&sa,FALSE,TRUE,NULL);
g_decEvent=CreateEvent(&sa,FALSE,FALSE,NULL);
addhandle=CreateThread(
&sa,
dwStackSize,
AddProc,
lpParameter,
dwCreationFlags,
&addThreadId);
// Sleep(20);
dechandle=CreateThread(
&sa,
dwStackSize,
DecProc,
lpParameter,
dwCreationFlags,
&decThreadId);
WaitForSingleObject(addhandle,INFINITE);
WaitForSingleObject(dechandle,INFINITE);
CloseHandle(addhandle);
CloseHandle(dechandle);
return 0;
}
DWORD WINAPI AddProc(
LPVOID lpParameter // thread data
)
{
int loop=200;
while(loop>0)
{
WaitForSingleObject(g_addEvent,INFINITE);
loop-=1;
WaitForSingleObject(hmutex,INFINITE);
g_share+=1;
printf("add proc loop: %d g_share:%d
",loop,g_share);
Sleep(10);
ReleaseMutex(hmutex);
SetEvent(g_decEvent);
}
return 0;
};
DWORD WINAPI DecProc(
LPVOID lpParameter // thread data
)
{
int loop=200;
while(loop>0)
{
WaitForSingleObject(g_decEvent,INFINITE);
loop-=1;
WaitForSingleObject(hmutex,INFINITE);
g_share-=1;
printf("dec proc loop: %d g_share:%d
",loop,g_share);
Sleep(10);
ReleaseMutex(hmutex);
SetEvent(g_addEvent);
}
return 0;
};
程序运行结果如下图所示:
使用互斥对象Mutex为什么不能实现线程同步?
[日志分享]
[日志信息]
该日志于 2009-02-26 21:17 由 redice 发表在 redice's Blog ,你除了可以发表评论外,还可以转载 “使用互斥对象Mutex为什么不能实现线程同步?” 日志到你的网站或博客,但是请保留源地址及作者信息,谢谢!! (尊重他人劳动,你我共同努力)
呵呵,谢谢
VaTG790i.最好的<a href=http://www.kyfei.com>网站推广软件</a>,
非常好
....................
;ui;普i;uighur;ui;ui;个
在unix网络编程中看到了关于TCP/IP的一些内容,我感觉还是写的不够。正在下载中,一定
下载地址呢