ImageVerifierCode 换一换
格式:DOCX , 页数:8 ,大小:19.27KB ,
资源ID:2209275      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-2209275.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Windows多线程编程.docx)为本站会员(b****1)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

Windows多线程编程.docx

1、Windows多线程编程shenzi Windows核心编程:用内核对象进行线程同步 1.概述 用户模式下的同步让线程保持在用户模式下,在用户模式下的进行线程同步的最大好处就是速度非常快。然而它们的确存在一些局限性,使用内核对象进行线程同步用途要广泛得多。然而使用内核对象进行线程同步,必须进行用户模式与内核模式的切换,所以性能上会大打折扣。 我们已经讨论了好几种内核对象,包括进程、线程以及作业。几乎所有这些内核对象都可以用来进行同步。对线程同步来说,这些内核对象中的每一种要么处于触发状态,要么处于未触发状态。Microsooft为每种对象创建了一些规则,规定如何在这两种状态之间进行转换。用内核

2、对象进行线程同步就是要用这些内核对象的规则为线程同步服务。2.等待函数 等待函数 使一个线程自愿进入等待状态,直到指定的内核对象被触发为止。注意,如果线程在调用一个等待函数的时候,相应的内核对象已经处于触发状态,那么线程时不会进入等待状态的。 DWORD WaitForSingleObject( HANDLE hObject, /标识要等待的内核对象,这个内核对象可以处于触发或未触发状态; DWORD dwMilliseconds); /指定线程最多愿意花多长的时间来等待对象被触发; 通常,我们会给dwMilliseconds传入INFINITE,但也可以传任何其它的值(以微妙微单位)。传IN

3、FINITE可能会有点危险。如果对象永远不被触发,那么调用线程将永远不会被唤醒它会一直阻塞在那里,但幸运的是,它并没有浪费宝贵的CPU时间。 DWORD dw = WaitForSingleObject(hProcess, 5000); switch (dw) case WAIT_OBJECT_0: / 等待对象被触发,即等待进程已终止; break; case WAIT_TIMEOUT: / 等待超时,即等待的进程在5000微妙内未终止; break; case WAIT_FAILED: / 无效的参数,如无效的进程句柄 break; 前述代码告诉系统,除非指定的进程已经终止或者等待时间已满

4、5000微妙,否则不应该对调用线程进行调度。如果进程已经终止,那么这个调用会在5000微妙内返回,如果进程尚未终止,那么这个调用大约会在5000微妙左右返回。注意,如果给dwMilliseconds传0,WaitForSingleObject总会立即返回,即使它要等待的条件还没有满足。 还有一个函数允许调用线程同时检查多个内核对象的触发状态: DWORD WaitForMultipleObjects( DWORD dwCount,/表示希望检查的内核对象的数量;最大值MAXIMUM_WAIT_OBJECTS=64 CONST HANDLE* phObjects,/指向内核对象句柄数组 BOOL

5、 bWaitAll,/TRUE,等待所有内核对象触发;FALSE,等待其中任一对象触发; DWORD dwMilliseconds); /指定线程最多愿意花多长的时间来等待对象被触发; HANDLE3; h0 = hProcess1; h1 = hProcess2; h2 = hProcess3; DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); switch (dw) case WAIT_FAILED: / Bad call to function (invalid handle?) break; case WAIT_TIMEOUT:

6、 / None of the objects became signaled within 5000 milliseconds. break; /指定具体哪个进程触发引起返回的 case WAIT_OBJECT_0 + 0: / The process identified by h0 (hProcess1) terminated. break; case WAIT_OBJECT_0 + 1: / The process identified by h1 (hProcess2) terminated. break; case WAIT_OBJECT_0 + 2: / The process i

7、dentified by h2 (hProcess3) terminated. break; 3.等待成功所引起的副作用 我们在调用WaitForSingleObject或WaitForMultipleObjects有的时候可能 会改变对象的状态。如果对象的状态发生了改变,我们称之为等待成功所引起的副作用。 举个例子,现在假设线程正在等待一个自动重置事件对象(稍后会讲到)。当事件对象被触发的时候,函数会检测到这一情况,这时它可以直接返回 WAIT_OBJECT_0给调用线程。但是,就在函数返回之前,它会使事件变为非触发状态这就是等待成功所引起的副作用。然而进程和线程对象就完全没有副作用,也就是

8、说,等待这些对象绝对不会改变对象的状态。4.事件内核对象 事件的触发表示一个操作已经完成。有两种不同类型的事件对象:手动重置事件 和自动重置事件。 当一个手动重置事件被触发的时候,正在等待该事件的所有线程都将变为可调度状态。而当自动重置事件被触发的时候,只有一个正在等待该事件的线程会变成可调度状态。 事件最通常的用途是,让一个线程执行初始化工作,然后再触发另一个线程,让它执行剩余的工作。以开始我么么你将事件初始化为为触发状态,然后当线程完成初始化工作的时候,触发事件。此时,另一个线程一直在等待该事件,它发现事件被触发,于是鞭策很能够可调度状态。第二个线程知道第一个线程已经完成了它的工作。 下面

9、是CreateEvent函数,用来创建一个事件内核对象: HANDLE CreateEvent( PSECURITY_ATTRIBUTES psa, BOOL bManualReset,/TRUE,创建手动重置事件;FALSE,创建自动重置事件。 BOOL bInitialState,/TRUE,初始化为触发状态;FALSE,初始化为未触发状态。 PCTSTR pszName); 一旦创建了事件,我们就可以直接控制它的状态。当调用SetEvent的时候,我们把时间变成触发状态: BOOL SetEvent(HANDLE hEvent); 当调用ResetEvent的时候,我们把时间变成未触发状

10、态: BOOL ResetEvent(HANDLE hEvent); Microsoft为自动重置事件 定义了一个等待成功所引起的副作用:当线程成功等到自动重置事件对象的时候,对象会自动地重置为未触发状态。这也是自动重置事件名字的由来。对自动重置事件来说,通常不需要调用 ResetEvent,这是因为系统会自动将事件重置。相反,Microsoft并没为手动重置事件对象定义一个等待成功所引起的副作用。5.可等待的计时器内核对象 可等待的计时器是这样一种内核对象,它们会在某个指定的事件触发,或没隔一段时间触发一次。它们通常用来在某个时间执行一些操作。 创建可等待的计时器: HANDLE Creat

11、eWaitableTimer( PSECURITY_ATTRIBUTES psa, BOOL bManualReset,/TRUE,手动重置计时器,FALSE,自动重置计时器; PCTSTR pszName); 当手动重置计时器被触发的时候,正在等待该计时器的所有线程都会变成可调度状态。当自动重置计时器被触发的时候,只有一个正在等待该计时器大的线程变成可调度状态。 在创建的时候,可等待的计时器对象总是处于未触发状态。调用一下函数来处罚计时器: BOOL SetWaitableTimer( HANDLE hTimer, const LARGE_INTEGER *pDueTime,/计时器第一次触

12、发的时间; LONG lPeriod,/第一次触发之后,计时器应该以怎样的频度触发; PTIMERAPCROUTINE pfnCompletionRoutine,/APC调用相关 PVOID pvArgToCompletionRoutine, BOOL bResume); 取消计时器,这样计时器就永远不会触发了,除非再调用SetWaitableTimer来对它进行重置: BOOL CancelWaitableTimer(HANDLE hTimer); 可等待计时器和用户计时器(通过SetTimer函数来设置)的最大区别在于用户计时器需要在应用程序中使用大量的用户界面基础设施,从而消耗更多的资源

13、。此外可等待计时器是内核对象,这意味着它们不仅可以在多个线程间共享,而且可以具备安全性。 6.信号量内核对象 信号量内核对象用来对资源进行计数。与其它所有内核对象相同,它们也包含一个使用计数,但他们还包含另外两个32位值:一个最大资源计数和一个当前资源计数。 信号量的规则如下: 如果当前资源计数大于0,那么信号量处于触发状态; 如果当前资源计数等于0,那么信号量处于未触发状态; 系统绝对不会让当前资源计数变为负数; 当前资源计数绝对不会大于最大资源计数; 创建信号量内核对象: HANDLE CreateSemaphore( PSECURITY_ATTRIBUTE psa, LONG lInit

14、ialCount,/资源初始计数 LONG lMaximumCount,/资源的最大计数 PCTSTR pszName); 如果等待函数发现信号量当前资源计数为0(信号量处于未触发状态),那么系统会让调用线程进入等待状态。当另一个线程将信号量的当前资源计数递增时,系统会记得那个还在等待的线程,使它们变成可调度状态(并相应递减当前资源计数)。 线程通过调用ReleaseSemaphore来递增心好像的当前资源计数: BOOL ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount,/把这个值加到资源计数上,通常为1 PLONG plPrev

15、iousCount);/返回当前资源计数的原始值; 7.互斥量内核对象 互斥量内核对象用来确保一个线程独占对一个资源的访问。互斥量与关键段的行为完全相同。但是,互斥量是内核对象,而关键段是用户模式下的同步对象。 互斥量的规则: 如果线程ID为0(无效线程ID),那么该互斥量不为任何线程所占用,它处于触发状态; 如果线程ID为非零值,那么有一个线程已经占用了该互斥量,它处于未触发状态; 与所有其它内核对象不同,操作系统对互斥量进行了特殊处理,允许它们违反一些常规的规则; 创建一个互斥量: HANDLE CreateMutex( PSECURITY_ATTRIBUTES psa, BOOL bIn

16、itialOwner,/指定是否为调用线程所有 PCTSTR pszName); 当目前占用访问权的线程不再需要访问资源的时候,它必须调用ReleaseMutex函数来释放互斥量: BOOL ReleaseMutex(HANDLE hMutex); 特征 互斥量 关键段 性能 慢 块 是否能跨进程使用 是 否 声明 HANDLE hmtx; CRITICAL_SECTION cs; 初始化 hmtx = CreateMutex (NULL, FALSE, NULL); InitializeCriticalSection(&cs); 清理 CloseHandle(hmtx); DeleteCri

17、ticalSection(&cs); 无限等待 WaitForSingleObject (hmtx, INFINITE); EnterCriticalSection(&cs); 0等待 WaitForSingleObject (hmtx, 0); TryEnterCriticalSection(&cs); 任意时间长度的等待 WaitForSingleObject (hmtx, dwMilliseconds); 不支持 释放 ReleaseMutex(hmtx); LeaveCriticalSection(&cs); 是否能同时等待其它 内核对象 是 (使用WaitForMultipleObj

18、ects 或类似函数) 否 表1:互斥量和关键段比较 8.线程同步对象速查表 对象 何时处于未触发状态 何时处于触发状态 成功等待的副作用 进程 当进程仍在运行的时候 当进程终止运行时(ExitProcess, Te rminateProcess) 无 线程 当线程仍在运行时 当线程终止运行时(ExitThread, TerminateThread) 无 作业 当作业尚未超时的时候 当作业超时的时候 无 文件 当I / O请求正在处理时 当I / O请求处理完毕时 无 控制台输入 不存在任何输入 当存在输入时 无 文件修改通知 没有任何文件被修改 当文件系统发现修改时 重置通知 自动重置事件

19、ResetEvent , PulseEvent或等待成功 当调用SetEvent / PulseEvent时 重置事件 手动重置事件 ResetEvent或PulseEvent 当调用SetEvent / PulseEvent时 无 自动重置等待计时器 CancelWaitableTimer或等待成功 当时间到时(SetWaitableTimer) 重置定时器 手动重置等待计时器 CancelWaitableTimer 当时间到时(SetWaitableTimer) 无 信号量 等待成功 当数量 0时(ReleaseSemaphore) 数量递减1 互斥对象 等待成功 当未被线程拥有时(Release互斥对象) 将所有权赋予线程 关键代码段(用户模式) 等待成功(Try)EnterCriticalSection) 当未被线程拥有时(LeaveCriticalSection) 将所有权赋予线程 SRWLock(用户模式)等待成功的时候(AcquireSRWLock(Exclusive)不为线程占用的时候(ReleaseSRWLock(Exclusive)把所有权交给线程条件变量(用户模式)等待成功地时候(SleepConditionVariable*)被唤醒的时候(Wake(All)ConditionVariable)没有表2:内核对象与线程同步

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2