WIN32多线程程序设计学习笔记(第四章 上)

原创 2007年09月17日 20:06:00
WIN32多线程程序设计学习笔记(第四章 上)
 
到目前为止,我已经知道如何创建线程,销毁线程及如何判断一个线程是否结束了;但运用线程,管理线程,如何使线程按自己意愿正确运行才是多线程程序设计的重点及难点。
 
大家知道,线程具有并发性,在同一时间段会存在多个线程,当这些线程同时存取同一数据时,就会有问题。就像在超市储物品一样,来的时候物品箱是空,转身拿物品准备储的时候,发现物品箱已被占用了。这时,物品箱就是我所说的同一数据,人指的就是线程了。
 
那么,如何让线程彼此互相合作,互不干扰呢?------协调线程的工作是由同步机制来完成的。正如书上所说:“有放多种同步机制可以运用。使用哪一种则完全视欲解决的问题而定。这些同步机制还能用各种方式组合在一起运用,以产生更精密的机制”。
 
首先,让我们看看最容易使用的一个同步机制;它包含同步机制的设计思想,拿握了它也就可以不费什么劲拿握其它的同步机制了。
1 Critical Sections(关键区域、临界区域)
程序片段:
       CRITICAL_SECTION        gBoxKey ;
       DWORD WINAPI ThreadFun(LPVOID n)
       {
              //进入关键区域(情景:关上物品箱,拨下钥匙)
              EnterCreiticalSection (&gBoxKey ) ;(1
                     //处理一些不可分割的操作。。。。。
                     //(情景:转身拿物品,储物品,去购物。。。。)
              //离开关键区域(情景:打开物品箱,拿出储存的物品,插上钥匙)                
              LeaveCreiticalSection (&gBoxKey) ;(2
       }
 
       void main()
       {
              //初始化全局锁 (情景:生成物品箱的钥匙)
              InitializeCriticalSection( &gBoxKey ) ;             
              //产生两个线程 (情景:准备两个人抢一个物品箱)
              HANDLE hMan1 = CreateThread(NULL,0,ThreadFun,…….);
              HANDLE hMan2 = CreateThread(NULL,0,ThreadFun,…….);
 
              CloseHandle(hMan1);
              CloseHandle(hMan2);
 
              //删除全局锁 (情景:删除物品箱的钥匙)
              DeleteCriticalSection( &gBoxKey ) ;
       }
 
按照上面的程序,我在笔记开头所描述的“超市储物品”的情况是不会发生的,不会再有物品箱被人抢走的可能。由于线程的并发性,从我看到一个空箱子到我将物品的放入物品箱中的这段时间内的操作应该是不可分割的;否则,我看到的物品箱就随时会被人抢走。那么如何保证操作是连续、不可分割呢?简单:看到空箱子,关上箱子,拨下钥匙(1),这时,别人就没办法使用这个箱子了。当我不再需要箱子的时候,打开箱子,插入钥匙(2),就可以让别人使用了。上述就是多线程处理共享资源的一个基本思路。
 
2 Mutexes(互斥器)
程序片段:
       HANDLE              hBoxKey ;
       DWORD WINAPI ThreadFun(LPVOID n)
       {
              //进入关键区域(情景:关上物品箱,拨下钥匙)
              WaitForSingleObject ( hMutex,INFINITE ) ;(1
                     //处理一些不可分割的操作。。。。。
                     //(情景:转身拿物品,储物品,去购物。。。。)
              /离开关键区域(情景:打开物品箱,拿出储存的物品,插上钥匙)                
              ReleaseMutex ( hMutex ) ;(2
       }
 
       void main()
       {
              //初始化全局锁 (情景:生成物品箱的钥匙)
              hBoxKey = CreateMutex(       NULL,FALSE,NULL );          
              //产生两个线程 (情景:准备两个人抢一个物品箱)
              HANDLE hMan1 = CreateThread(NULL,0,ThreadFun,…….);
              HANDLE hMan2 = CreateThread(NULL,0,ThreadFun,…….);
 
              CloseHandle(hMan1);
              CloseHandle(hMan2);
 
              //删除全局锁 (情景:删除物品箱的钥匙)
              CloseHandle( hBoxKey ) ;
       }
看到没?无论从共享资源的思路了,还是从程序代码的编制上,使用Mutexes与使用Critical Sections几乎都没有什么区别;但作为 Mutexes机制的提出肯定是有其原因的;我们来看这样的一个情形,当我拿走钥匙以后,因为某些因素再也不能回来了,那么这个箱子便再也不能被使用。也就是说,进入Critical Sections线程若中途当掉了,那么别了线程是再也进不了Critical Sections(一个资源就这样浪费了),那些需要进入Critical Sections的线程会停在入口不再执行,线程永远都结束不了。
怎么办?(WaitForSingleObject解决
还记得上一章学过的WaitForSingleObject吗?上一章主要用它等待线程的结束,但这个函数的作用不仅限于此,在这里,我们再前进一小步,探究WaitForSingleObject这个函数的妙用。
原型:
DWORD WaitForSingleObject ( HANDLE hObject DWORD  time ) ;
hObject:等待对象的handle(代表一个核心对象),在上一章中代表线程handle,注意没有,hObject代表一个核心对象,也就是说,只要是核心对象,WaitForSingleObject都能处理,处理的原则是“当核心对象被激发时,函数返回”(有多少种核心对象?及核心对象对激发的定义见P76)。
在这里,我遇到了一个叫mutex核心对象,mutex对激发的定义是:“当没有任何线程拥有该mutex,而且有一个线程正以Wait…()等待mutex,该mutex就会短暂地出现激发状态,使Wait…()得以返回, 那么在其它的情况,mutex处于未激发状态
 
好了,我们又进一步的了解了WaitForSingleObject函数,那么,如何解决Critical Sections所遇到的因难呢?当拥有mutex线程结束前没有调用ReleaseMutex(不管该线程是当了,还是忘记调用ReleaseMutex),那么其它正以WaitForSingleObject()等待此mutex的线程就会收到WAIT_ABANDONED_0。有了这个值,我就解开难题了。
程序片段:
DWORD        rc    =       WaitForSingleObject( hMutex ) ;
If ( rc  == WAIT_OBJECT_0 )
{
              //正常的处理
}
else
{
              If ( rc  == WAIT_ABANDONED_0 )
{
                     //没有正常的释放mutex(比如拥有mutex的线程死了)
}
}
 
我想,从笔记的角度来看,上面对mutex描述已经可以帮助我很快的上手使用了,至于对mutex更详细的说明,还是要看看书.(当然,希望我的这一段描述能帮助你理解mutexJ)
      
总结一下:
CRITICAL_SECTION                             Mutex 核心对象
 
InitializeCriticalSection()                                   CreateMutex()
                                                                      OpenMutex()
 
EnterCriticalSection()                                      WaitForSingleObject()
 
LeaveCriticalSection()                                      ReleaseMutex()
 
DeleteCriticalSection()                                    CloseHandle()
 
附注:以上正文纯属加强记忆所做笔记,内容或有不详,甚至错误,请阅者见谅,匆见怪!!!
 

《win32多线程程序设计》学习笔记二

一、产生一个线程 1、产生一个线程(并因而成就一个多线程程序),是以CreateThread()函数作为开始。此函数原型如下: 二、使用多线程的结果 1、多线程程序无法预...

《win32多线程程序设计》学习笔记五

一、干净的终止一个线程 1、利用TerminateThread()放弃一个线程  注:尽量不要使用TerminateThread()函数。 2、几个可能的终止一个线程的方法  1)、使用信...

《win32多线程程序设计》学习笔记四

一、Critical Sections

转载:《Win32多线程程序设计》学习笔记 第10章 MFC 中的线程

《Win32多线程程序设计》学习笔记 第10章 MFC 中的线程 如果要在MFC程序中产生一个线程,而该线程将调用MFC函数或者使用MFC的任何数据,那么你必须以AfxBeginThre...

《Win32多线程程序设计》读书笔记(一)

1,可以使用GetExitThreadCode函数获取线程函数结束时的返回值 2,多线程程序设计成功的关键: 2.1,各线程的数据要分离开来,避免使用全局变量 2.2,不要在线程之间共享GDI对象 2...

win32多线程程序设计笔记(第三章)

一、复习第二章 在第二章中,讲到了两种等待线程的技术:         1)使用Sleep()函数——问题是你不可能事先知道什么事情要等待多久         2)使用busy loop,通过不断...

《Win32多线程程序设计》读书笔记之内核对象

所谓句柄(Handle),其实就是指针,指向操作系统内存空间中的某样东西,为了维护系统的完整性与安全性,不允许直接取得。 内核对象与GDI对象不同,内核对象由KERNEL32.DLL管理,而GD...

win32多线程程序设计笔记(第五章)

前面章节介绍了线程创建等过程,现在的问题是:如何在某个线程内终止另外一个正在运行的线程? windows核心编程中提到终止运行线程的方法:        1)线程函数自己返回;     ...

win32多线程程序设计笔记(第六章上)

我们知道当程序调用I/O设备处理一些事情时,让主程序停下来干等I/O的完成是没有效率的。。对这个问题有下面几种解决方法: 方法一:使用另一个线程进行I/O。问题是在主线程中操控多个线程,如何设置同步...

win 32多线程程序设计读书笔记

一直不是很熟悉windows下的编程,借着学习侯捷老师翻译的《win32 多线程程序设计》来完成操作系统的作业。 1.今天学到的比较重要的概念是核心对象(一下大部分话出自该书): 核心对象可以有...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WIN32多线程程序设计学习笔记(第四章 上)
举报原因:
原因补充:

(最多只允许输入30个字)