x()函数并传递一个互斥对象的句柄作为参数时,这种拥有关系就被解除,互斥对象重新进入发信号状态。
可以调用函数CreateMutex()来创建一个互斥量。当使用完互斥对象时,应当调用CloseHandle()来关闭它。
3. 信号量
另一种使线程同步的技术是使用信号量对象。它是在互斥的基础上建立的,但信号量增加了资源计数的功能,预定数目的线程允许同时进入要同步的代码。可以用CreateSemaphore()来创建一个信号量对象,
因为只允许一个线程进入要同步的代码,所以信号量的最大计数值(lMaximumCount)要设为1。ReleaseSemaphore()函数将使信号量对象的计数加1;
记住,最后一定要调用CloseHandle()函数来释放由CreateSemaphore()创建的信号量对象的句柄。
★★★WaitForSingleObject函数的返值:
WAIT_ABANDONED指定的对象是互斥对象,并且拥有这个互斥对象的线程在没有释放此对象之前就已终止。此时就称互斥对象被抛弃。这种情况下,这个互斥对象归当前线程所有,并把它设为非发信号状态;
WAIT_OBJECT_0 指定的对象处于发信号状态;
WAIT_TIMEOUT等待的时间已过,对象仍然是非发信号状态;
——————————————————————————————————————————————
VCL支持三种技术来达到这个目的:
(2) 使用critical区
如果对象没有提高内置的锁定功能,需要使用critical区,Critical区在同一个时间只也许一个线程进入。为了使用Critical区,产生一个TCriticalSection全局的实例。TcriticalSection有两个方法,Acquire(阻止其他线程执行该区域)和Release(取消阻止)
每个Critical区是与你想要保护的全局内存相关联。每个访问全局内存的线程必须首先使用Acquire来保证没有其他线程使用它。完成以后,线程调用Release方法,让其他线程也可以通过调用Acquire来使用这块全局内存。
警告:Critical区只有在所有的线程都使用它来访问全局内存,如果有线程直接调用内存,而不通过Acquire,会造成同时访问的问题。例如:LockXY是一个全局的Critical区变量。任何一个访问全局X, Y的变量的线程,在访问前,都必须使用Acquire
LockXY.Acquire;{ lock out other threads }
try
Y := sin(X);
finally
LockXY.Release;
end
临界区主要是为实现线程之间同步的,但是使用的时候注意,一定要在用此临界对象同步的线程之外建立该对象(一般在主线程中建立临界对象)。
————————————————————————————————————————————————
线程同步使用临界区,进程同步使用互斥对象。
Delphi中封装了临界对象。对象名为TCriticalSection,使用的时候只要在主线程当中建立这个临界对象(注意一定要在需要同步的线程之外建立这个对象)。具体同步的时候使用Lock和Unlock即可。
而进程间同步建立互斥对象,则只需要建立一个互斥对象CreateMutex. 需要同步的时候只需要WaitForSingleObject(mutexhandle, INFINITE) unlock的时候只需要ReleaseMutex(mutexhandle);即可。
有很多方法, 信号灯, 临界区, 互斥对象,此外, windows下还可以用全局原子,共享内存等等. 在windows体系中, 读写一个8位整数时原子的, 你可以依靠这一点完成互斥的方法. 对于能够产生全局名称的方法能够可以在进程间同步上(如互斥对象), 也可以用在线程间同步上;不能够产生全局名称的方法(如临界区)只能用在线程间同步上.