间已过,对象仍然是非发信号状态再次声明,当一个互斥对象不再被一个线程所拥有,它就处于发信号状态。此时首先调用WaitForSingleObject()函数的线程就成为该互斥对象的拥有者,此互斥对象设为不发信号状态。当线程调用ReleaseMutex()函数并传递一个互斥对象的句柄作为参数时,这种拥有关系就被解除,互斥对象重新进入发信号状态。
注意除WaitForSingleObject()函数外,你还可以使用WaitForMultipleObject()和MsgWaitForMultipleObject()函数,它们可以等待几个对象变为发信号状态。这两个函数的详细情况请看Win32 API联机文档。
3. 信号量
另一种使线程同步的技术是使用信号量对象。它是在互斥的基础上建立的,但信号量增加了资源计数的功能,预定数目的线程允许同时进入要同步的代码。可以用CreateSemaphore()来创建一个信号量对象,其声明如下:
function
和CreateMutex()函数一样,CreateSemaphore()的第一个参数也是一个指向TSecurityAttribute s记录的指针,此参数的缺省值可以设为nil。
lInitialCount参数用来指定一个信号量的初始计数值,这个值必须在0和lMaximumCount之间。此参数大于0,就表示信号量处于发信号状态。当调用WaitForSingleObject()函数(或其他函数)时,此计数值就减1。当调用ReleaseSemaphore()时,此计数值加1。
参数lMaximumCount指定计数值的最大值。如果这个信号量代表某种资源,那么这个值代表可用资源总数。
参数lpName用于给出信号量对象的名称,它类似于CreateMutex()函数的lpName参数。
——————————————————————————————————————————
★★★关于线程同步:
Synchronize()是在一个隐蔽的窗口里运行,如果在这里你的任务很繁忙,你的主窗口会阻塞掉;Synchronize()只是将该线程的代码放到主线程中运行,并非线程同步。
临界区是一个进程里的所有线程同步的最好办法,他不是系统级的,只是进程级的,也就是说他可能利用进程内的一些标志来保证该进程内的线程同步,据Richter说是一个记数循环;临界区只能在同一进程内使用;临界区只能无限期等待,不过2k增加了TryEnterCriticalSection函数实现0时间等待。
互斥则是保证多进程间的线程同步,他是利用系统内核对象来保证同步的。由于系统内核对象可以是有名字的,因此多个进程间可以利用这个有名字的内核对象保证系统资源的线程安全性。互斥量是Win32 内核对象,由操作系统负责管理;互斥量可以使用WaitForSingleObject实现无限等待,0时间等待和任意时间等待。
1. 临界区
临界区是一种最直接的线程同步方式。所谓临界区,就是一次只能由一个线程来执行的一段代码。如果把初始化数组的代码放在临界区内,另一个线程在第一个线程处理完之前是不会被执行的。在使用临界区之前,必须使用InitializeCriticalSection()过程来初始化它。
在第一个线程调用了EnterCriticalSection()之后,所有别的线程就不能再进入代码块。下一个线程要等第一个线程调用LeaveCriticalSection()后才能被唤醒。
2. 互斥
互斥非常类似于临界区,除了两个关键的区别:首先,互斥可用于跨进程的线程同步。其次,互斥能被赋予一个字符串名字,并且通过引用此名字创建现有互斥对象的附加句柄。
提示:临界区与事件对象(比如互斥对象)的最大的区别是在性能上。临界区在没有线程冲突时,要用10 ~ 15个时间片,而事件对象由于涉及到系统内核要用400~600个时间片。
当一个互斥对象不再被一个线程所拥有,它就处于发信号状态。此时首先调用WaitForSingleObject()函数的线程就成为该互斥对象的拥有者,此互斥对象设为不发信号状态。当线程调用ReleaseMute