Mutex的使用机制:
1. 有一个mutex,此时没有任何线程拥有它,此时它处于非激发状态。
2. 某个线程调用WaitforSingleObject()或任何其它的wait…函数,并指定该mutex的handle为参数
3. win32于是将该mutex的拥有权给予这个线程,然后将此mutex设为激发状态,于是wait..函数返回
4. wait..函数返回后,win32立刻又将mutex设为非激发状态,是任何处于等待状态下的其它线程没有办法获得其拥有权
5. 获得该mutex的线程调用Release,将mutex释放掉。于是循环到第一步。
如果线程拥有一个mutex,而在结束前没有调用releaseMutex,mutex不会被摧毁,该mutex会被win32视为“未被拥有”以及“未被激发”,下一个等待中的线程会被以WAIT_ABANDONED_0通知。如果是WaitForMultipleObjects()等待辞mutex,函数返回值介于WAIT_ABANDONED_0和WAIT_ABANDONED_0+n之间,n是指handle数组的元素个数。
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName );
参数
lpMutexAttributes:安全属性。Null表示使用默认的属性。
bInitialOwner:如果你希望调用这个函数的线程拥有mutex,就将此值设为true
lpName:互斥对象的名称
返回值
如果成功,则返回一个handle,否则返回null。
函数说明:
如果指定的mutex名称已经存在,win32会给你一个mutex handle,而不会为你产生一个新的mutex。调用GetLastError会传回ERROR_ALREADY_EXISTS。当你不需要mutex时,你可以调用closehandle()将它关闭。
BOOL ReleaseMutex(
HANDLE hMutex //欲释放mutex的handle
);
返回值
如果成功,则返回true,否则返回false。
3.信号量(Semaphores)
Mutex是semaphore的一种退化,如果你产生一个semaphore并令最大值为1,那它就是个mutex。因此,mutex又常被称为binary semaphore。在许多系统中,semaphore常被使用,因为mutex可能并不存在,在win32中semaphore被使用的情况就少得多,因为mutex存在的原因。
一旦semaphore的现值降到0,就表示资源已经耗尽。此时任何线程如果调用Wait…函数,必然要等待,直到某个锁定被解除。
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName
)
参数:
lpSemaphoreAttributes:安全属性,null表示使用默认属性。
lInitialCount:初始值,必须>=0,并且<= lMaximumCount
lMaximumCount:最大值,也就是在同一时间内能够锁住semaphore的线程数
lpName:名称,这个值也可以是null。
返回值:
如果成功就返回一个handle,否则返回null。如果semaphore名称已经存在,函数还是会成功,GetLastError会返回ERROR_ALREADY_EXISTS
函数说明:
产生一个semaphore。
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);
参数:
hSemaphore:semaphore的句柄。
lReleaseCount:semaphore现值的增量,通常是1,该值不可以是负值或者0
lpPreviousCount:返回semaphore增加前的现值
返回值:
如果成功就返回true,否则返回false。
函数说明:
三、事件(Events)
事件(Event)是一种核心对象,它的唯一目的就是成为激发状态或未激发状态。这两种状态完全在你的掌握之下,不会因为Wait…函数的调用而变化。
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
LPCTSTR lpName
);
参数:
lpEventAttributes:安全属性,null表示使用默认属性。
bManualReset :
此值为false,表示event变成激发状态后,自动重置为非激发状态;
此值为true,表示不会自动重置,必须靠程序(调用ResetEvent)操作才能将激发状态的event重置为非激发状态。
bInitialState :初始状态,true一开始处于激发状态,false一开始处于非激发状态
lpName :Event对象名
返回值:
如果成功就返回一个handle,否则返回null。如果event名称已经存在,函数还是会成功,GetLastError会返回ERROR_ALREADY_EXISTS
BOOL SetEvent(HANDLE hEvent);
//把event对象设为激发状态
BOOL ResetEvent(HANDLE hEvent);
//把event对象设为非激发状态
BOOL PulseEvent(HANDLE hEvent );
//如果event的bManualReset 为true:把event对象设为激发状态,唤醒所有等待中的线程,然后event恢复为非激发状态
//如果event的bManualReset 为false:把event对象设为激发状态,唤醒一个等待中的线程,然后event恢复为非激发状态
5.使用Synchronize方法
这个方法用于访问VCL主线程所管理的资源,其方法的应用是: 第一步:把访问主窗口(或主窗口控件资源)的代码放到线程的一个方法中; 第二步:是在线程对象的Execute方法中,通过Synchronize方法使用该方法。 实例: procedure Theater.Execute; begin Synchronize(update); end;
procedure Theater.update; begin ......... end;
这里通过 Synchronize使线程方法update同步。
6、使用VCL类的Look方法
在Delphi的IDE提供的构件中,有一些对象内部提供了线程的同步机制,工作线程可以直接使用这些控件,比如:Tfont,Tpen,TBitmap,TMetafile,Ticon等。另外,一个很重要的控件对象叫TCanvas,提供了一个Lock方法用于线程的同步,当一个线程使用此控件对象的时候,首先调用这个对象的Lock方法,然后对这个控件进行操作,完毕后再调用Unlock方法,释放对控间的控制权。 例如: CanversObject.look; try 画图 finally CanversObject.unlock; end; {使用这个保护机制,保证不论有没有异常,unlock都会被执行否则很可能会发生死锁。在多线程设计的时候,应该很注意发生死锁的问题}
四、线程的优先级:
在多线程的情况下,一般要根据线程执行任务的重要性,给线程适当的优先级,一般如果量的线程同时申请CPU时间,优先级高的线程优先。
优先权类别(Priority Class)
Win32提供四种优先权类别,每一个类别对应一个基本的优先权层次。
表格5-1优先权类别
大部分程序使用NORMAL_PRIORITY_CLASS。优先权类别是进程的属性之一,利用SetPriorityClass和GetPriorityClass函数可以调整和获取该值。
优先权层次(priority Level)
线程的优先权层次使你能够调整同一个进程内的各线程的相对重要性。一共七种优先权层次:
表格5-2 利用SetThreadPriority和GetThreadPriority函数可以调整和获取该值
在Windows下,给线程的优先级分为30级,而Delphi中Tthread对象相对简单的把优先级分为七级。也就是在Tthread中声明了一个枚举类型TTthreadPriority:
type TTthreadPriority(tpidle,tpLowest,tpLower,tpNormal, tpHight,tpHighest,tpTimecrital)
分别对应的是最低(系统空闲时有效,-15),较低(-2),低(-1),正常(普通0),高(1),较高(2),最高(15)。 设置优先级可使用thread对象的priority属性: threadObject.priority:=Tthreadpriority(级别);
BOOL SetThreadPriority(
HANDLE hThread, //欲调整优先权的那个线程的句柄
int nPriority //表格5-2所显示的值
);
Int GetThreadPriority(
HANDLE hThread //线程的句柄
);
返回值是线程的优先级。
原文:http://www.cnblogs.com/bjxsky/p/4616728.html