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

📄 16.txt

📁 网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
💻 TXT
字号:
16.2.2  利用关键代码段实现线程同步
码段实现线程同步
下面就利用关键代码段来实现线程同步。首先新建一个空的 Wm32 Console Application 类型的工
程,工程名取为: Critical。并为该工程添加一个 C I I源文件: Critical.cpp,然后就在此文件
中添加具体的实现代码,可以复制上面编写的 Event.cpp文件中的内容,并删除其中与事件对象相
关的代码,然后添加使用临界区对象实现线程同步的代码,结果如例 16-4所示。 
fJlJ16-4 

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

DWORD W工 NAPI FunlProc( LPVOID lpParameter // thread data 
DWORD W工 NAPI Fun2Proc( LPVO工 D lpParameter // thread data 
int tickets=lOOi 
CR工 T工 CAL_SECTION .g_cSi 

void main() 
HANDLE hThreadl; 
HANDLE hThread2; 
hThreadl=CreateThread(NULL, O, FunlProc , NULL , O, NULL); 
hThread2=CreateThread(NULL, O, Fun2Proc , NULL , 0 , NULL); 
CloseHandle(hThreadl); 
CloseHandle(hThread2); 

InitializeCriticalSection(&g一cs) ; 
Sleep(4000); 

DeleteCriticalSection(&g_cs); 
DWORD WINAPI FunlProc( . LPVO工 D lpParameter // thread data 
while (TRUE) 
{ 
EnterCriticalSection(&g_cs); 
Sleep(l); 
if(tickets>O) 
{ 

Sleep(l) ; 
cout<<"threadl sell ticket : "<<tickets--<<endl; 
LeaveCriticalSection(&g一cs) ; 

} 
else 

LeaveCriticalSection(&g_cs) ; 
break; 

return 0; 
DWORD WINAP工 Fu口 2Proc( LPVOID lpParameter // thread data 
while(TRUE) 
{ 
EnterCriticalSection(&g_cs); 

~~ I 601 


第16章线程罔步 

S1eep (1) ; 
工f(t工ckets>O} 
S1eep(1} ; 
cout<< "thread2 se11 ticket : "<<tickets--<<end1 ; 
LeaveCritica1Section(&g_cs) ; 

e1se 
LeaveCritica1Section(&g一cs} ; 
break; 

return 0; 
在上述如例 16-4所示代码中与Event程序相同的部分就不再讲述,这里仅解释新添加
的与关键代码段相关的代码。因为多个线程都需要访问临界区对象,所以将它定义为全局对象,即
上述代码中定义的 CRITICAL SECTION类型的对象: g_cs。
然后按照上面讲述的关键段代码段使用的过程,在 main函数中首先需要调用 
InitializeCriticalSection函数创建临界区对象,并在程序退出前,需要调用 
DeleteCriticalSection函数释放没有被任何线程使用的临界区对象的所有资源。
在主线程创建的两个线程中,在进入关键代码段访问受保护的代码之前,需要调用 
EnterCriticalSection函数,以判断能否得到指定的临界区对象的所有权,如果无法得到该所有权,
那么 EnterCriticalSection函数会一直等待,从而导致线程暂停运行;如果能够得到该所有权,那
么该线程就进入到关键代码段中,访问受保护的资源。当该访问完成之后,需要调用
LeaveCriticalSection函数,释放指定的临界区对象的所有权。 
Build并运行Critical程序,将会看到程序结果正常。
在使用临界区对象编程时,有一点需要注意,有时在得到临界区对象的所有权之后,可能忘记释放
该所有权,这将造成什么样的后果呢?我们可以把如例 16-4所示代码中线程1函数FunlPrω中的
LeaveCriticalSection函数调用注释起来,然后再次运行Critical程序,将会看到始终是线程1在销
售火车票,线程2没有得到销售的机会,程序结果如图 16.3所示。

图 16.3线程l没有释放临界区对象所有权时的程序结果

602 	I ~~~ 
-1 VC++深λ详解

为了验证线程2确实没有得到执行关键代码段的机会,在如例 16-4所示代码中线程2函数Fun2Proc
中,在while循环结束后,输出一句话,即在该函数的retum语旬之前添加下面这条语句: 
cout<<"thread2 is runningl"<<endl; 
如果线程2得到了执行关键代码段的机会,它就会打印出这句话:"tkead2is running!"。
再次运行Critical程序,将会发现始终没有看到"thread2 is running! "这句话,这说明线程2始终
没有得到执行关键代码段的机会。这主要是因为线程l获得了临界区对象的所有权,虽然线程l执行
完成之后就退出了,但是因为该线程一直未释放临界区对象的所有权,导致线程2始终无法得到该所
有权,只能一直等待,无法执行下面的关键代码段,直到进程退出时,该线程也就退出了。这就好
像在公用电话亭使用电话这种资源时,当一个人打完电话离开电话亭走了,但由于某种原因,他把
电话亭锁起来了,这时其他想要进入该电话亭使用电话的人始终判断出该电话亭有人,一直进不去,
虽然实际上这时先前使用电话的那个人已经走了。同样地,这时虽然线程1的运行己经终止并退出了,
但线程2仍然无法得到运行的机会。 

⌨️ 快捷键说明

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