Windows核心编程 (6)

线程与内核对象的同步
1.用户方式的线程同步机制具有速度快的有点,但是它也具有其局限性。例如,互锁函数家族只能在单值上运行,关键 代码只能对单个进程中的线程进行同步而且很容易陷入死锁状态。内核对象机制的适应性要远远优于用户方式机制,实际上,内核对象机制唯一不足之处是它的速度 比较慢。

2.The WaitForSingleObject() function returns when one of the following occurs: The specified object is in the signaled state. The time-out interval elapses. 当调用WaitForSingleObject(hProcess,INFINITE)时等待到hPress句柄表示的进程运行终止为止。
3.DWORD WaitForMultipleObjects(DWORD dwCount,CONST HANDLE* phObjects,BOOL fWaitAll,DWORD dwMilliseconds)函数可以用来允许调用线程同时查看若干个内核对象的已通知状态。
4.,进程内核对象总是在未通知状态中创建的。当进程终止运行时,操作系统自动使该进程的内核对象处于已通知状态。一旦进程内核对象得到通知,它将永远保持这种状态,它的状态永远不会改为未通知状态。
5.下面的内核对象可以处于已通知状态或未通知状态:
■ 进程■ 文件修改通知■ 线程■ 事件■ 作业■ 可等待定时器■ 文件■ 信标■ 控制台输入■ 互斥对象
6.对于有些内核对象来说,成功地调用WaitForSingleObject和WaitForMultipleObjects,实际上会改变对象的状态。
7.在所有的内核对象中,事件内核对象是个最基本的对象。它们包含一个使用计数(与所有内核对象一样),一个用于指明该事件是个自动重置的事件 还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。当人工重置的事件得到通知时,等待该事件的所有线程均变为 可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
8.线程调用CreateEvent函数创建事件内核对象。其他进程中的线程可以获得对该对象的访问权,方法是使用在pszName参数中传递 的相同值,使用继承性,使用DuplicateHandle函数等来调用CreateEvent,或者调用OpenEvent,在pszName参数中设 定一个与调用CreateEvent时设定的名字相匹配的名字。与所有情况中一样,当不再需要事件内核对象时,应该调用CloseHandle函数。一旦 事件已经创建,就可以直接控制它的状态。当调用SetEvent时,可以将事件改为已通知状态,当调用ResetEvent函数时,可以将该事件改为未通 知状态。通常没有必要为自动重置的事件调用ResetEvent函数,因为系统会自动对事件进行重置。但是,Microsoft没有为人工重置的事件定义 成功等待的副作用。
9.PulseEvent函数使得事件变为已通知状态,然后立即又变为未通知状态,这就像在调用SetEvent后又立即调用ResetEvent函数一样。
10.The lstrcmpi function compares two character strings. The comparison is not case sensitive.
11._tcsrev() Reverse characters of a string._strrev的宏.#include <tchar.h>
12.The EndDialog function destroys a modal dialog box, causing the system to end any processing for the dialog box.
13.The SystemTimeToFileTime function converts a system time to a file time. The LocalFileTimeToFileTime function converts a local file time to a file time based on the Coordinated Universal Time (UTC).
14.线程通过调用CreateWaitableTimer函数创建等待定时器内核对象->进程可以调用OpenWaitableTimer函数取得与进程相关的等待定时器句柄->调用SetWaitableTimer函数来设置定时器合适成为已通知状态。
15.同样,定时器分为人工重置定时器和自动重置定时器。
16.由于FILETIME结构和LARGE_INTEGER结构拥有相同的二进制格式,都包含两个32位的值。因此可以像下面这样将 FILETIME结构的地址直接传递给SetWaitableTimer:SetWaitableTimer(hTimer, (PLARGE_INTEGER)&ftUTC, 6*60*60*1000, NULL, NULL, FALSE); 实际上,这是我最初的做法。但是这是个大错误。虽然FILETIME和LARGE_INTEGER结构采用相同的二进制格式,但是这两个结构的调整要求不 同。所有FILETIME结构的地址必须从一个32位的边界开始,而所有LARGE_INTEGER结构的地址则必须从64位的边界开始。调用 SetWaitableTimer函数和给它传递一个FILETIME结构时是否能够正确地运行,取决于FILETIME结构是否恰好位于64位的边界 上。但是,编译器能够确保LARGE_INTEGER结构总
是从64位的边界开始,因此要进行的正确操作(也就是所有时间都能保证起作用的操作) 是将FILETIME的成员拷贝到LARGE_INTEGER的成员中,然后将LARGE_INTEGER的地址传递给 SetWaitableTimer。注意,x86处理器能够悄悄地处理未对齐的数据引用。因此当应用程序在x86 CPU上运行时,将FILETIME的地址传递给SetWaitablrTimer总是可行的。但是,其他处理器,
如Alpha处理器,则无法像x86处理器那样悄悄地处理未对齐的数据引用。实际上,大多数其他处理器都会产生一个EXCEPTION_DATATYPE_MISALIGNMENT异常,它会导致进程终止运行。
17.如果不设置定时器应该第一次报时的绝对时间,也可以让定时器在一个相对于调用SetWaitableTimer的时间进行报时。只需要在pDueTime参数中传递一个负值。传递的值必须是以100ns为间隔。
18.CancelWaitableTimer函数用于取出定时器的句柄并将它撤销。除非重新调用SetWaitableTimer函数,否则定时器不会再报时。
19.The GetDateFormat function formats a date as a date string for a specified locale. The function formats either a specified date or the local system date.The GetTimeFormat function formats a time as a time string for a specified locale. The function formats either a specified time or the local system time.
20._tcscat函数append a string.
21.让等待定时器给APC项排队:Microsoft允许定时器在定时器得到通知的时候给调用SetWaitableTimer函数的线程的 异步过程调用(APC)进行排队。此时必须给定时器传递APC例程的地址。注意调用线程必须处于待命状态,即调用SetWaitableTimer后调用 SleeEx,SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx, or WaitForSingleObjectEx 等函数。而且线程不应该等待定时器的句柄,也不应该以待命的方式等待定时器,例如WaitForSingleObjectEx,因为调用 WaitForSingleObjectEx函数实际上是两次等待定时器,一次是以待命方式等待,一次是等待内核对象句柄。当定时器变为已通知状态时,等 待就成功了,线程被唤醒,这将使该线程摆脱待命状态,而APC例程则没有被调用。前面讲过,通常没有理由使用带有等待定时器的APC例程,因为你始终都可 以等待定时器变为已通知状态,然后做你想要做的事情。Each thread has its own APC queue.
22.定时器常常用于通信协议。
23.用户定时器(用SetTimer函数尽心设置)与等待定时器最大的差别是,用户定时器需要在应用程序中设置许多附加的用户界面结构,这使 定时器变得资源更加紧密。另外等待定时器属于内核对象,这意味着它可以供多个线程共享,并且是安全的。用户定时器能够生成WM_TIMER消息,这些消息 返回给调用SetTimer的线程和创建窗口的线程。因此,当用户定时器报时的时候,只有一个线程得到通知。如果执行与用户界面相关的时间,以便对定时器 作出响应,那么使用用户定时器来组织代码结构可能更加容易些,因为使用等待定时器时,线程必须既要等待各种消息,又要等待内核对象(如果要改变代码的结 构,可以使用MsgWaitForMultipleObjects函数)。
24.信标内核对象用于对资源进行计数。CreateSemaphore函数用于创建信标内核对象。其他进程可以调用OpenSemaphore来获得信标的句柄。调用ReleaseSemphore函数,线程就可以对信标的当前资源数量进行递增。
25.The Win32® API provides a set of wait functions to allow a thread to block its own execution. There are three types of wait functions: single-object,multiple-object,alertable。In an alertable wait operation, the function can return when the specified conditions are met, but it can also return if the system queues an I/O completion routine or an APC for execution by the waiting thread.
26.互斥对象(mutex)内核对象能够确保线程拥有对单个资源的互斥访问权。互斥对象的行为特性与关键代码段相同,但是互斥对象属于内核对 象,而关键代码段则属于用户方式对象。相关的函数分别为:CreateMutex,OpenMutex和ReleaseMutex。
27.互斥对象不同于所有其他内核对象,因为互斥对象有一个“线程所有权”的概念。本章介绍的其他内核对象中,没有一种对象能够记住哪个线程成功地等待到该对象,只有互斥对象能够对此保持跟踪。
28.因此,如果在释放互斥对象之前,拥有互斥对象的线程终止运行(使用ExitThread、TerminateThread、 ExitProcess或TerminateProcess函数),那么互斥对象和正在等待互斥对象的其他线程将会发生什么情况呢?答案是,系统将把该互 斥对象视为已经被放弃——拥有互斥对象的线程决不会释放它,因为该线程已经终止运行。由于系统保持对所有互斥对象和线程内核对象的跟踪,因此它能准确的知 道互斥对象何时被放弃。当一个互斥对象被放弃时,系统将自动把互斥对象的ID复置为0,并将它的递归计数器复置为0。
29.The HeapAlloc function allocates a block of memory from a heap. The allocated memory is not movable.
30.The MoveMemory function moves a block of memory from one location to another.

31.其他线程同步函数:异步设备I/O,WaitForInputIdle(如果父进程的线程想要知道子进程何时完成初始化,唯一的办法是等 待,直到子进程不再处理任何输入为止。因此,当调用CreateProcess后,父进程的线程就调用 WaitForInputIdle),MsgWaitForMultipleObjects(创建窗口和执行与用户界面相关的任务的线程,应该调用 MsgWaitForMultipleObjectsEx函数,而不应该调用WaitForMultipleObjects函数,因为后面这个函数将使线 程的用户界面无法对用户作出响应),SingleObjectAndWait(对一个内核对象发出通知并等待另一个对象)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值