⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 15.4.3 利用互斥对象实现线程同步.txt

📁 网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
💻 TXT
📖 第 1 页 / 共 2 页
字号:
15.4.3 利用互斥对象实现线程同步
互斥对象 (mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥对象包含一
个使用数量,一个线程 B和一个计数器。其中 ID用于标识系统中的哪个线程当前拥有互斥对象,计
数器用于指明该线程拥有互斥对象的次数。
为了创建互斥对象,需要调用函数: CreateMutex,该函数可以创建或打开一个命名的或匿名的互斥
对象,然后程序就可以利用该互斥对象完成线程间的同步。 CreateMutex函数的原型声明如下所述: 
HANDLE CreateMutex( 
LPSECURITY_ATTRIBUTES lpMutexAttributes , 
BOOL binitial Own er, 
LPCTSTR lpNarne , 

该函数具有三个参数,其含义分别如下所述: 
. lpMutexAttributes 
一个指向 SECURITY ATTRmUTES结构的指针,可以给该参数传递 NULL值,让互斥对象使用默认的安
全性。 
. blnitia10wner 
BOOL类型,指定互斥对象初始的拥有者。如果该值为真,则创建这个互斥对象的线程获得该对象的
所有权;否则,该线程将不获得所创建的互斥对象的所有权。 
. lpName 
指定互斥对象的名称。如果此参数为 NULL.则创建一个匿名的互斥对象。
如果调用成功,该函数将返回所创建的互斥对象的句柄。如果创建的是命名的互斥对象,并且在 
CreateMutex函数调用之前,该命名的互斥对象存在,那么该函数将返回己经
存在的这个互斥对象的句柄,而这时调用 GetLas tError函数将返回 ERROR_ALREADY_ 

EXISTS。
另外,当线程对共享资源访问结束后,应释放该对象的所有权,也就是让该对象处于
己通知状态。这时需要调用ReleaseMutex函数,该函数将释放指定对象的所有权。该函数的原型声
明如下所示: 
BOOL ReleaseMutex ( HANDLE hMutex ); 
ReleaseMutex函数只有一个 HANDLE类型的参数,即需要释放的互斥对象的句柄。该函数的返回值是
BOOL类型,如果函数调用成功,返回非0值:否则返回0值。
另外,线程必须主动请求共享对象的使用权才有可能获得该所有权,这可以通过调用 
WaitForSingleObject函数来实现,该函数的原型声明如下所述: 
DWORD WaitForSingleObject{ HANDLE hHandle , DWORD dwMilliseconds }; 
该函数有两个参数,其含义分别如下所述: 
. hHandle 
所请求的对象的句柄。本例将传递己创建的互斥对象的句柄:陆1utex。一旦互斥对象处于有信号状
态,则该函数就返回。如果该互斥对象始终处于无信号状态,即未通知的状态,则该函数就会一直
等待,这样就会暂停线程的执行。 
. dwMilliseconds 
指定等待的时间间隔,以毫秒为单位。如果指定的时间间隔己过,即使所请求的对象仍处于无信号
状态, WaitForSingleObject函数也会返回。如果将此参数设置为 0,那么 WaitForSingleObject
函数将测试该对象的状态并立即返回;如果将此参数设置为.J..l".1 "U ....1. J. L , 则该函数会
永远等待,直到等待的对象处于有信号状态才会返回。
调用WaitForSingleObject函数后,该函数会一直等待,只有在以下两种情况下才会返回: 
·
指定的对象变成有信号状态: 

·
指定的等待时间间隔己过。


如果函数调用成功,那么WaitForSingleObject函数的返回值将表明引起该函数返回的事件,表15.1
列出了该函数可能的返回值:
表 15.1 WaitForSingleObject函数的返回值

返回值 说明  
WAIT OBJECT 0  所请求的对象是有信号状态  
WAIT TIMEOUT  指定的时间间隔己过,并且所请求的对象是无信号状态 
WAIT ABANDONED  所谓求的对象是一个互斥对象,并且先前俯有该对象的线程在终止前没旬释放该
对象.这 时,该对象的所有权将授予当前调用线程,并且将该互斥对象被设置为无信号状态 

下面,我们修改上述如例 15-2所示的MultiThread程序代码,利用互斥对象来实现线程|司步。最终
的实现代码如例 15-3所示。 
例 15-3 

#include <windows.h> 
#include <iostream.h> 

DWORD WINAPI FunlProc( 

LPVOID lpParameter 11 thread data 
DWORD WINAPI Fu口 2Proc( LPVO工 o lpParameter 11 thread data 
int index=0; 
int tickets=100; 
HANDLE hMutex; 
void main () 
{ 

HANDLE hThread1; 
HANDLE hThread2; 

11创建线程 
hThread1=CreateThread(NULL, 0, Fun1Proc , NULL , 0, NULL) ; 
hThread2=CreateThread(NULL, 0 , Fun2Proc , NULL , 0 , NULL) ; 
CloseHandle(hThread1) ; 
CloseHandle(hThread2) ; 

11创建互斥对象 
hMutex=CreateMutex(NULL, FALSE , NULL); 
Sleep(4000) ; 
11线程 1的入口函数 
 
DWORD WINAPI Fun1Proc( LPVOID lpParameter 11 thread data 
Wwhile (TRUE) 
waitForSingleObject( hMutex,INFINITE) ; 
if (tickets>0) 
Sleep (1) ; 
cout<<"threadl sell ticket : "<<tickets--<<endl; 

else 
break; 
ReleaseMutex(hMutex); 

return 0 ; 
11线程 2的入口函数 
DWORD WINAPI Fun2Proc( 
LPVO工D lpParameter // thread data 
while{TRUE) 
WaitForSingleObject{hMutex,INFINITE) ; 
if (tickets>O) 

Sleep{1) ; 
cout<< "thread2 sell ticket : "<<tickets--<<endl; 

else 
break: 
ReleaseMutex(hMutex); 
return 0 ; 
在上述例 15-3所示代码中,首先定义了一个HANDLE类型的全局变量: hMutex,用来保存即将创建的
互斥对象句柄。
接下来,在mam函数中,调用CreateMutex函数创建一个匿名的互斥对象。
然后在线程1和线程2中,在需要保护的代码前面添加WaitForSingleObject函数的调
用,让其请求互斥对象的所有权,这样线程1和线程2就会一直等待,除非所请求的对象处于有信号
状态,该函数才会返回,线程才能继续往 F执行,即才能执行受保护的代码。因此,在如例15-3所
示代码中,在线程l和线程2访问它们共享的全局变量tickets之前,添加了下述语句,实现线程同步: 
WaitForSingleObject{hMutex,INFINITE) ; 
这样,当执行到这条语句时,线程 l和线程2就会等待,除非所等待的互斥对象: hMutex处于有信号
状态,线程才能继续向下执行,即才能访问 tickets变量,完成火车票的销售工作。
当对所要保护的代码操作完成之后,应该调用ReleaseMutex函数释放当前线程对互斥对象的所有权,
这时,操作系统就会将该互斥对象的线程ID设置为0,然后将该互斥对象设置为有信号状态。使得其
他线程有机会获得该对象的所有权,从而获得对共享资源的访问。
下面,我们来分析一下如例 15-3所示程序的执行过程。在创建互斥对象时,第二个参数传递的是 
FALSE值,这表明当前没有线程拥有这个互斥对象,于是,操作系统就会将该互斥对象设置为有信号
状态。当第一个线程开始运行时,进入 while循环后,调用 WaitForSingleObject函数,因为这时
互斥对象处于有信号状态,所以该线程就请求到了这个互斥对象,操作系统就会将该互斥对象.的线
程设置为线程1的ID,接着,操作系统会将这个互斥对象设置为未通知状态。线程1继续往下运行,
调用 Sleep函数,于是暂停执行。操作系统就会选择线程 2开始执行,该线程的执行过程也是一样
的,进入到 while 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -