多线程常用的内核对象:CreateEvent事件,CreateMutex互斥,CreateSemaphore信号,CreateWaitableTimer计时器
{建立事件} function CreateEvent( lpEventAttributes: PSecurityAttributes; {!} bManualReset: BOOL; bInitialState: BOOL; lpName: PWideChar ): THandle; stdcall; {建立互斥} function CreateMutex( lpMutexAttributes: PSecurityAttributes; {!} bInitialOwner: BOOL; lpName: PWideChar ): THandle; stdcall; {建立信号} function CreateSemaphore( lpSemaphoreAttributes: PSecurityAttributes; {!} lInitialCount: Longint; lMaximumCount: Longint; lpName: PWideChar ): THandle; stdcall; {建立等待计时器} function CreateWaitableTimer( lpTimerAttributes: PSecurityAttributes; {!} bManualReset: BOOL; lpTimerName: PWideChar ): THandle; stdcall;
上面的四个系统内核对象(事件、互斥、信号、计时器)都是线程同步的手段, 从这也能看出处理线程同步的复杂性; 不过这还不是全部, Windows Vista 开始又增加了 Condition variables(条件变量)、Slim Reader-Writer Locks(读写锁)等同步手段.
不过最简单、最轻便(速度最快)的同步手段还是 CriticalSection(临界区), 但它不属于系统内核对象, 当然也就没有句柄、没有 TSecurityAttributes 这个安全属性, 这也导致它不能跨进程使用; 不过写多线程时一般不用跨进程啊, 所以 CriticalSection 应该是最常用的同步手段.
------------------------------------------------------------------------------------------------------------------------------------------------------------
先介绍临界区(不是内核对象,不能跨进程):作用,独占共享资源的的访问权(同一时间内只有一个线程可以修改共享资源)
更多理解祥见:http://www.cnblogs.com/760044827qq/p/4158640.html
"临界区"(CriticalSection): 当把一段代码放入一个临界区, 线程执行到临界区时就独占了, 让其他也要执行此代码的线程先等等;
var CS: TRTLCriticalSection; {声明一个 TRTLCriticalSection 结构类型变量; 它应该是全局的} InitializeCriticalSection(CS); {初始化} EnterCriticalSection(CS); {开始: 轮到我了其他线程走开} LeaveCriticalSection(CS); {结束: 其他线程可以来了} DeleteCriticalSection(CS); {删除: 注意不能过早删除}
Delphi 在 SyncObjs 单元给封装了一个 TCriticalSection 类,用法和API类似。
------------------------------------------------------------------------------------------------------------------------------------------------------------
等待函数
function WaitForSingleObject(
hHandle: THandle; {要等待的对象句柄}
dwMilliseconds: DWORD {等待的时间, 单位是毫秒;如果是INFINITE,就是一直等。}
): DWORD; stdcall; {返回值如下:}
WAIT_OBJECT_0 {等着了, 本例中是: 等的那个进程终于结束了}
WAIT_TIMEOUT {等过了点(你指定的时间), 也没等着}
WAIT_ABANDONED {好不容易等着了, 但人家还是不让咱执行; 这一般是互斥对象}
------------------------------------------------------------------------------------------------------------------------------------------------------------
原理分析: 互斥对象是系统内核对象, 各线程都可以拥有它, 谁拥有谁就能执行; 执行完毕, 用 ReleaseMutex 函数释放拥有权, 以让其他等待的线程使用. 其他线程可用 WaitForSingleObject 函数排队等候(等候也可以理解为排队申请).
使用过程:
var hMutex: THandle; {应该先声明一个全局的互斥句柄} CreateMutex {建立一个互斥对象} WaitForSingleObject {用等待函数排队等候} ReleaseMutex {释放拥有权} CloseHandle {最后释放互斥对象}
ReleaseMutex、CloseHandle 的参数都是 CreateMutex 返回的句柄, 关键是 CreateMutex 函数:
function CreateMutex( lpMutexAttributes: PSecurityAttributes; bInitialOwner: BOOL; {是否让创建者(此例中是主线程)拥有该互斥对象} lpName: PWideChar {可以给此互斥对象取个名字, 如果不要名字可赋值为 nil} ): THandle; { 1、第一个参数前面说过. 2、第二个参数在这里一定要是 False, 如果让主线程拥有互斥, 从理论上讲, 得等程序退出后其他线程才有机会; 取值 False 时, 第一个执行的线程将会最先拥有互斥对象, 一旦拥有其他线程就得先等等. 3、第三个参数, 如果给个名字, 函数将从系统中寻找是否有重名的互斥对象, 如果有则返回同名对象的存在的句柄; 如果赋值为 nil 将直接创建一个新的互斥对象; 下个例子将会有名字. }Delphi 在 SyncObjs 单元给封装了一个 TCriticalSection 类,用法和API类似。
------------------------------------------------------------------------------------------------------------------------------------------------------------
来源:https://www.cnblogs.com/760044827qq/p/4158633.html