线程与内核对象的同步小结

线程与内核对象的同步

1为什么使用内核对象实现线程同步

 

1.1用户模式下实现线程同步特点

 

(1)同步速度快

(2)互锁函数族只能对单值进行操作,无法是线程进入等待状态。

(3)临界区可以使线程进入等待状态,但是只能用于同一个进程的多个线程。由于无法设置超时操作,因此容易进入死锁状态。

 

1.2内核模式下实现线程同步特点

 

(1)内核对象机制的唯一缺点:速度慢。

(2)优点:适用性强

 

2等待函数

 

2.1 WaitForSingleObject

 

等待函数使线程进入等待状态,等待一个特定的内核对象变成已通知状态。当线程等待对象的状态为未通知状态时,不能调度这个,线程,一旦内核对象变成已通知状态,线程标志变成可调度。

DWORD  WaitForSingleObject(

             HANDLE  hObject,

             DWORD  dwMilliseconds);

第一个参数hObject标识一个支持通知/未通知状态的内核对象;第二个参数dwMillseconds指明等待对象变成已通知状态所需的等待时间。当第二个参数为INFINITE(-1)时,说明线程可以无限等待,直到进程终止运行。通常情况下,会使用INFINITE,如果对象一直未通知,线程将一直处于死锁状态,但是不会浪费处理器时间。

函数返回值:

WAIT_OBJECT_0               //等待对象变成已通知状态

WAIT_TIMEOUT                //等待超时

WAIT_FAILED                     //传递错误参数,通过GetLastError()了解详情

 

2.2 WaitForMultipleObject

 

         DWORD WaitForMultipleObject(

                   DWORD dwCount,

                   CONSTHANDLE*  phObjects,

                   BOOL fWaitAll,

                   DWORD dwMilliseconds);

         第一个参数指明调用线程所查看的内核对象的数量,在0-MAXIMUM_WAIT_OBJECTS(windows定义为64)之间;第二个参数是指向内核对象句柄数组的指针;第三个参数fWaitAll指示两种成功等待方式,一种需要所有内核对象变成已通知,另一种需要任意一个内核对象变成已通知;第四个参数同上。

         返回值:

         WAIT_TIMEOUT;     

         WAIT_FAILED;

         WAIT_OBJECT_0;(fWaitall为ture)

         WAIT_OBJECT_0到WAIT_OBJECT_0+dwCount-1之间的值(fWaitall为false时,指示哪个对象变成已通知状态)

 

3事件内核对象

 

         事件内核对象是所有内核对象中最基本的。事件内核对象包含一个使用计数(所有内核对象都有),一个布尔值,指示这个事件是自动重置事件还是人工重置事件。以及另外一个指示事件处于已通知状态还是未通知状态的布尔值。

         两种事件对象:

人工重置事件:得到通知时,等待这个事件的所有线程变成可调度线程。

自动重置事件:得到通知时,等待这个事件的所有线程只有一个变成可调度线程。

 

3.1 创建事件内核对象

 

         下面是用于创建事件内核对象的CreateEvent函数:

         HANDLE CreateEvent(

                   PSECURITY_ATTRIBUTES  psa,

                   BOOL  fManualReset,

                   BOOL  fInitialState,

                   PSTSTR  pszName)

         第一个参数(PSECURITY_ATTRIBUTES)安全性描述符:描述创建对象的进程,以及哪些进程可以访问对象,哪些不可以访问;第二个参数fManualReset参数是一个布尔值,用于指明创建人工重置事件还是自动重置事件;第三个参数fInitialState指明这个事件初始化为已通知状态还是未通知状态。第四个参数为事件命名;

 

3.2 内核对象的使用

 

         其他进程中的线程可以通过pszName参数中传递的相同值,使用继承性,使用DuplicateHandle等函数来获得对这个对象的访问权。或者通过调用OpenEvent,传递的pazName一致即可。

         HANDLE  OpenEvent(

                   DWORD  fdwAccess,

                   BOOL  bInherit,

                   PCTSTRpszName);

         创建事件后,就可以直接控制这个事件的状态。可以调用SetEvent将事件的状态改为已通知,调用ResetEvent改为未通知状态:

         BOOL  SetEvent(HANDLE  hEvent);

         BOOL  ResetEvent(HANDLE  hEvent);

         不在需要使用该事件时,调用CloseHandle函数。

 

4 等待定时器内核对象          

 

等待定时器是在某个时间或按照规定时间间隔,发出自己的信号通知的内核对象。通常使用这些内核对象,在某个时间执行某个操作。

 

4.1创建等待定时器

 

HANDLE  CreateWaitableTimer(

         PSECURITY_ATTRIBUTES  psa,

         BOOL fManualReset,

         PSTSTR pszName);

进程也可以通过OpenWaitableTimer函数,来获得与进场相关的等待定时器句柄。

HANDLE  OpenWaitableTimer(

         DWORD dwDesiedAccess,

         BOOL bInheritHandle,

         PSTSTR pszName)

 

4.2使用定时器

 

等待定时器总是设置为未通知状态。可以调用SetWaitableTimer函数,来确定定时器何时变成已通知状态:

BOOLSetWaitalbeTimer(

            HANDLE  hTime,

            const  LARGE_INTERGER*pDueTime

            LONG  lPeriod,

             PTIMERAPCOUTINE  pfnCompletionRoutine,

            PVOID pvArgToCompletionRoutine,

            BOOL  fResume);

         hTime:指明要设置的定时器对象

         pDueTime:指明定时器第一次报时时间;

         pPeriod:指明定时器第一次报时之后,定时器再次报时的时间间隔   

 

5.信号量内核对象

 

         信号量内核对象用来对资源进行计数,它与其他内核对象一样,包含一个使用计数。同时包含两个带符号的32位数:一个最大资源数量,一个当前资源数量。

信号量的使用规则:

l  当前资源的数量大于0时,发出信号量信号;

l  当前资源数量等于0时,不发出信号量信号;

l  当前资源数量不能为负值;

l  当前资源数量不能大于最大资源数量

使用信号量时,不能将信号量的对象的使用数量和当前资源数量混淆。

 

5.1信号量创建

 

         下面是创建信号量内核对象的函数:

         HANDLECreateSemaphore(

                   PSECURITY_ATTRIBUTE  psa,

                   LONG  lInitialCount,

                   LONG  lMaximumCount,

                   PCTSTR  pszName);

         llMaximumCount表示应用程序处理的最大资源数量,这个参数是带符号的32位值,因此最多可以拥有2147483647个资源;

         lInitialCount参数指明开始时(当前)资源中有多少资源可供使用。

         调用OpenSemaphore函数,另外的进程也能获取自己与现有信号量相关的句柄:

         HANDLEOpenSemaphore(

                   DWORD  fdwAccess,

                   BOOL  bInitialCount,

                   PCTSTR  pszName);

         可以调用ReleaseSemphore函数,对信号量的当前资源数量进行递增:

         BOOLReleaseSemaphore(

                   HANDLE  hsem,

                   LONG  lReleaseCount,

                   PLONG  plPreviousCount);

这个函数的功能是将参数lReleaseCount的值添加给信号量当前的资源数量,通常为1.没有函数可以查询信号量当前的资源数量。


具体题目:
在操作系统的进程管理中,若系统中有10个进程使用互斥资源R,每次只允许3个进程进入互斥段(临界区),则信号量S的变化范围是______(1):若信号量S的当前值为-2,则表示系统中有______(2)个正在等待该资源的进程。
(1)A.-7~1    B.-7~3    C.-3~0    D.-3~10
(2)A.0    B.1    C.2    D.3

B:S<0后请求R的进程将被阻塞,此时应该有3个进程获得资源。
C:第一个分配后,S=2;第三个分配后,S=0;第四个进程请求时S=-1,等待资源;S=-2时既有两个进程在等待。

关键是要分清:先S减一,还是先分配资源

6.互斥对象内核对象

6.1互斥对象

互斥对象确保线程能够互斥的访问一个资源,这也是这个对象如此命名的原因。互斥对象包含一个使用计数,一个线程ID和一个递归计数器。

互斥对象的使用规则如下:

l  若线程ID是0,即无效ID,互斥对象不能被任何线程拥有。并且发出这个对象的通知信号。

l  若线程ID是个非0值,那么互斥对象被某一个线程拥有,并且不发出这个对象的通知信号。

l  互斥对象在操作系统中拥有特殊的代码,允许互斥对象违反正常的规则,这与其他内核对象不同。

使用互斥对象之前,调用CreateMutex函数创建互斥对象。

HANDLECreateMutex(

          PSECURITY_ATTRIBUTES  pas;

          BOOL  fInitialOwner,

          PCTSTR  pszName);

另外的进程通过Ope nMutex获得自身与现有互斥对象关联的句柄

HANDLEOpenMutex(

         DWORD  fdwAccess,

         BOOL bIniheritHandle,

         PCTSTR pszName);

互斥对象所进行的所有检查和修改操作都是以原子方式进行的。一旦线程等待到了一个互斥对象,线程就拥有对所保护资源的独占访问权。线程调用ReleaseMutex函数释放互斥对象,将互斥对象的引用计数-1。

BOOL ReleaseMutex(HANDLE  hMutex);

“异常”:对于互斥对象来说,存在内核对象已通知或未通知的异常情况。假如一个线程正在等待一个未通知的互斥对象,那么通常将这个线程置于等待状态。然而系统会查看试图获得互斥对象的线程ID,并与互斥对象记录的线程ID进行比较.如果两者相同,那么即使互斥对象处于未通知状态,系统也允许这个线程保持可调度状态。

这个“异常”情况不适用于其他内核对象。因此要使递归计数器的值大于1,唯一的方法是使线程多次等待相同的互斥对象。释放时需要多次调用ReleaseMutex,直到计数器的值为0。

 

6.2 释放问题

 

         互斥对象和其他内核对象不同,有一个“线程所有权”的问题,其他内核对象无法记住哪个线程正在拥有这个对象,而互斥对象能够对此保持跟踪。这也是互斥对象拥有异常规则的原因。异常规则是的线程在对象没有发出通知时,获取这个对象。

当拥有互斥对象的线程在释放这个对象前终止运行,系统则把这个互斥对象视为已经放弃。然后系统检查是否有等待这个互斥对象的线程,并选择其中一个。将互斥对象的线程ID设置为选定线程的ID,计数为1.

在这个过程中,等待函数返回的不是WAIT_OBJTCT_0,而是WAIT_ABANDONED,表示这个互斥对象被另一个线程占有,而另一个进程在释放对象前终止。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值