用内核对象同步线程

 

       用户方式同步具有速度快的优点。但是它的缺点特是显而易见的。
  • 首先,用互锁函数家族的时候,这些函数只能用在单值数据上
  • 如果用关键代码段的话,只能对单个进程中的线程进行同步。而且容易出现死琐,而且不能设置等待时间
那么内核对象就克服了用户方式同步的几个缺点,能够在不同进程间对线程实施同步,而且处理完全不止在单值数据上。但是内核方式同步线程时,必须将线程进入到内核方式,这样就使处理速度大大降低。这也是内核方式的缺点,所以还是能用用户方式处理的就用用户方式来处理。
现在来说下一个很多内核对象都具有的特性,这就是 signaled/nonsignaled 特性。
这个特性是这样的:在内核对象处于运行状态时,他就是 nonsignaled 状态,当内核对象运行结束时,就会处于 signaled 状态。在内核对象中是用一个 bool 值来表示的。所以查看内核对象的状态很容易。只要查这个值就可以了。所以当线程要等待的内核对象处于 signaled 状态时,那么这个线程就可以被 CPU 调度,否则处于等待状态。
拥有这个特性的内核对象有:

·  Processes
·  File change notifications
·  Threads
·  Events
·  Jobs
·  Waitable timers
·  Files
·  Semaphores
·  Console input
·  Mutexes

现在就来重点说下 Event,waitable timer,Semaphore,Mutex. 这四个用的比较多。
在说这四个内核对象之前先来说下能让线程进入等待状态的函数,也就是去等待上面四个内核对象的状态的函数。他们有
DWORD WaitForSingleObject(HANDLE hObject,DWORD dwMillisecounds)
参数:
  • 1个参数就是要等待的对象的HANDLE,可以是上面四个中的一个。
  • 2个参数是等待超时时间。
返回值
  • WAIT_OBJECT_0//成功等待。也就是内核对象已经为signaled,线程成为可调度线程
  • WAIT_TIMEOUT//因为超时,线程重新唤醒,成为可调度的
  • WAIT_FAILED//将一个错误的值传递给WaitForSingleObject,比如传递了一个无效句柄。
DWORD WaitForMultipleObjects(DWORD dwCount,CONST HANDLE *phObjects,BOOL fWaitAll,DWORD dwMillisecounds)
参数:
  • dwCount  //想要让函数查看的内核对象的数目,这个值必须在1MAXIMUN_WAIT_OBJECTS(64)
  • phObjects    //指向内核对象句柄的数组的指针
  • fWaitAll      //如果为TRUE,就是等待到所有内核对象都signaledFALSE则是只要有一个signaled就唤醒
  • dwMillisecounds     //超时时间
返回值:
WaitForSingleObject 一样。只是,如果 fWaitAll==false 。那么如果想得到哪个对象 signaled 就可以将返回值剪去 WAIT_OBJECT_0 。(前提是,返回值即不是 WAIT_TIMEOUT 也不是 WAIT_FAILED
其实再调用上面两个函数时,如果等待成功(就是返回值为 WAIT_OBJECT_0 ),会对内核对象产生一个副作用。有的内核对象的副作用就是改变的内核对象的状态(比如自动清楚内核对象)。有的内核对象则没有任何副作用(比如线程,进程内核对象)。
下面就来逐一介绍 Event,Waitable timer,Semaphrone,Mutex 对象
先是 Event 对象。 Event 对象是最基本的内核对象。它包括:
1.         使用计数器
2.       自动重置 / 人工重置开关
3.       signaled/nonsignal 开关
1 3 不用多介绍。  重点说下 2 。什么叫自动重置?就是所有等待的线程,当 Event 对象变成 signaled 状态时,只会随即的挑选一个线程进入可调度状态。然后 Event 对象会被自动置为 nonsignaled 状态。而人工重置是当 Event 对象变成 signaled 时候,所有等待的线程都会被置为可调度状态。 CPU 会给他们都分配时间片。而且不会自动将 Event 状态置为 nonsignaled 。要通过 ResetEvent Event 变为 nonsignaled
至于创建 Event 内核对象 CreateEvent 函数,可以查找 MSDN
然后就是 WaitableTimer 内核对象。
CreateWaitableTimer OpenWaitableTimer 的使用可以查找 MSDN 。重点说下设置 WaitableTimer
设置 WaitableTimer 使用 SetWaitbaleTimer 。原形如下:
BOOL SetWaitableTimer(
    HANDLE hTimer, // handle to a timer object
    const LARGE_INTEGER *pDueTime, // when timer will become signaled
    LONG lPeriod, // periodic timer interval
    PTIMERAPCROUTINE pfnCompletionRoutine, // pointer to the completion routine
    LPVOID lpArgToCompletionRoutine, // data passed to the completion routine
    BOOL fResume // flag for resume state
   );
参数:
  • *pDueTime是等待定时器第1次报时的时间。可以为这个参数传递0,表示调用函数的时候就报时。或者传递一个负值,表示调用这个函数开始延迟n*100ns后开始第1次报时。
  • pfnCompletionRoutine指向一个函数的地址。如果这项不为NULL,那么当定时器报时的时候,会讲这个函数放入线程的APC队列。(什么是APC会在以后详细介绍)
下面再来说下  Semaphore
Semaphroe 的作用是为一个资源计数,而这个资源又是多个的。比如说你想对一个拥有 10 个元素的数组进行同步。那么就可以用 Semaphore 。当 10 个元素都被占用的时候。 Semaphore 就处于 nonsignaled 状态,反之,有元素可以被处理的时候就处于 nignaled 状态。
Semapore 包括:
1.       使用计数器
2.       最大资源数量
3.       当前可使用资源数量
他的使用规则是:
1.       当前资源大于 0 ,发出信标信号(处于 signaled 状态)
2.       当前资源等于 0 ,不发出信号
3.       0<= 当前资源 <= 最大资源
CreateSemaphore OpenSemaphore ReleaseSemaphore 可以查看 MSDN
ReleaseSemaphore 是将 Semaphore 的可使用资源进行增加。
最后就是 Mutex 了。 Mutex 是使用的最多的线程同步内核对象。它的作用是保证线程对单个资源的互斥访问权。它包括:
  • 使用计数器
  • 拥有Mutex的线程ID
  • 递归计数器//该线程拥有互斥对象的次数
Mutex 的使用规则是:
  • 线程ID0,互斥对象不被任何线程所拥有,并且发出该互斥对象的通知信号
  • 线程ID不为0,那么线程就拥有该互斥对象,不发出通知信号
CreateMutx OpenMutex ReleaseMutex 查看 MSDN
下面是互斥对象与关键代码段的比较

Characteristic
Mutex
Critical Section
Performance
Slow
Fast
Can be used across process boundaries
Yes
No
Declaration
HANDLE hmtx;
CRITICAL_SECTION cs;
Initialization
hmtx= CreateMutex (NULL, FALSE, NULL);
InitializeCriticalSection(&cs);
Cleanup
CloseHandle(hmtx);
DeleteCriticalSection(&cs);
Infinite wait
WaitForSingleObject (hmtx, INFINITE);
EnterCriticalSection(&cs);
0 wait
WaitForSingleObject (hmtx, 0);
TryEnterCriticalSection(&cs);
Arbitrary wait
WaitForSingleObject (hmtx, dwMilliseconds);
Not possible
Release
ReleaseMutex(hmtx);
LeaveCriticalSection(&cs);
Can be waited on with other kernel objects
Yes (use WaitForMultipleObjects or similar function)
No

 
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值