第8章 互斥信号量管理

第8章 互斥信号量管理
第8章 互斥信号量管理

第8章互斥型信号量管理

任务可以用互斥型信号量实现对共享资源的独占式处理。mutex是二值信号量。

mutex可以在应用程序中用于降解优先级反转问题。

互斥型信号量由3个元素组成:

1个标志,指示mutex是否可以使用(0或1);

1个优先级,准备一旦高优先级的任务需要这个mutex,赋给占有mutex的任务;

1个等待该mutex的任务列表。

对于互斥型信号量提供6种服务:OSMutexCreate(),OSMutexDel(),OSMutexPend(),OSMutexPost(),OSMutexAccept(),OSMutexQuery()。

mutex只能供任务使用,用于处理共享资源。

8.00 建立一个互斥型信号量, OSMutexCreate()

程序清单 L8.2建立一个信号量

OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)

{

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR cpu_sr;

#endif

OS_EVENT *pevent;

if (OSIntNesting > 0) {

*err = OS_ERR_CREATE_ISR;

return ((OS_EVENT *)0);

}

#if OS_ARG_CHK_EN > 0

if (prio >= OS_LOWEST_PRIO) {

*err = OS_PRIO_INVALID;

return ((OS_EVENT *)0);

}

#endif

OS_ENTER_CRITICAL();

if (OSTCBPrioTbl[prio] != (OS_TCB *)0) {

OS_EXIT_CRITICAL();

*err = OS_PRIO_EXIST;

return ((OS_EVENT *)0);

}

OSTCBPrioTbl[prio] = (OS_TCB *)1;

pevent = OSEventFreeList;

if (pevent == (OS_EVENT *)0) {

OSTCBPrioTbl[prio] = (OS_TCB *)0;

OS_EXIT_CRITICAL();

*err = OS_ERR_PEVENT_NULL;

return (pevent);

}

OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; OS_EXIT_CRITICAL();

pevent->OSEventType = OS_EVENT_TYPE_MUTEX;

pevent->OSEventCnt = (prio << 8) | OS_MUTEX_AVAILABLE;

pevent->OSEventPtr = (void *)0;

OS_EventWaitListInit(pevent);

*err = OS_NO_ERR;

return (pevent);

}

8.01 删除一个互斥型信号量, OSMutexDel()

#if OS_MUTEX_DEL_EN

OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)

{

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR cpu_sr;

#endif

BOOLEAN tasks_waiting;

INT8U pip;

if (OSIntNesting > 0) {

*err = OS_ERR_DEL_ISR;

return (pevent);

}

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) {

*err = OS_ERR_PEVENT_NULL;

return ((OS_EVENT *)0);

}

if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {

*err = OS_ERR_EVENT_TYPE;

return (pevent);

}

#endif

OS_ENTER_CRITICAL();

if (pevent->OSEventGrp != 0x00) {

tasks_waiting = TRUE;

} else {

tasks_waiting = FALSE;

}

switch (opt) {

case OS_DEL_NO_PEND:

if (tasks_waiting == FALSE) {

pip = (INT8U)(pevent->OSEventCnt >> 8); OSTCBPrioTbl[pip] = (OS_TCB *)0;

pevent->OSEventType = OS_EVENT_TYPE_UNUSED;

pevent->OSEventPtr = OSEventFreeList;

OSEventFreeList = pevent;

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return ((OS_EVENT *)0);

} else {

OS_EXIT_CRITICAL();

*err = OS_ERR_TASK_WAITING;

return (pevent);

}

case OS_DEL_ALWAYS:

while (pevent->OSEventGrp != 0x00) {

OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX); }

pip = (INT8U)(pevent->OSEventCnt >> 8); OSTCBPrioTbl[pip] = (OS_TCB *)0;

pevent->OSEventType = OS_EVENT_TYPE_UNUSED;

pevent->OSEventPtr = OSEventFreeList;

OSEventFreeList = pevent;

OS_EXIT_CRITICAL();

if (tasks_waiting == TRUE) {

OS_Sched();

}

*err = OS_NO_ERR;

return ((OS_EVENT *)0);

default:

OS_EXIT_CRITICAL();

*err = OS_ERR_INVALID_OPT;

return (pevent);

}

}

#endif

8.02 等待一个互斥型信号量, OSSemPend()

程序清单 L8.4 等待一个互斥型信号量

void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

{

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR cpu_sr;

#endif

INT8U pip;

INT8U mprio;

BOOLEAN rdy;

OS_TCB *ptcb;

if (OSIntNesting > 0) {

*err = OS_ERR_PEND_ISR;

return;

}

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) {

*err = OS_ERR_PEVENT_NULL;

return;

}

if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {

*err = OS_ERR_EVENT_TYPE;

return;

}

#endif (1) OS_ENTER_CRITICAL();

if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) ==

OS_MUTEX_AVAILABLE) {

pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;

pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;

pevent->OSEventPtr = (void *)OSTCBCur;

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return;

}

pip = (INT8U)(pevent->OSEventCnt >> 8);

mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);

ptcb = (OS_TCB *)(pevent->OSEventPtr);

if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) {

if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) { if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) {

OSRdyGrp &= ~ptcb->OSTCBBitY;

}

rdy = TRUE;

} else {

rdy = FALSE;

}

ptcb->OSTCBPrio = pip;

ptcb->OSTCBY = ptcb->OSTCBPrio >> 3;

ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];

ptcb->OSTCBX = ptcb->OSTCBPrio & 0x07;

ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];

if (rdy == TRUE) {

OSRdyGrp |= ptcb->OSTCBBitY;

OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

}

OSTCBPrioTbl[pip] = (OS_TCB *)ptcb;

}

OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; OSTCBCur->OSTCBDly = timeout; OS_EventTaskWait(pevent); OS_EXIT_CRITICAL();

OS_Sched(); OS_ENTER_CRITICAL();

if (OSTCBCur->OSTCBStat & OS_STAT_MUTEX) { OS_EventTO(pevent);

OS_EXIT_CRITICAL();

*err = OS_TIMEOUT; return;

}

OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

}

8.03 释放一个互斥型信号量, OSMutexPost()

INT8U OSMutexPost (OS_EVENT *pevent)

{

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR cpu_sr;

#endif

INT8U pip;

INT8U prio;

if (OSIntNesting > 0) {

return (OS_ERR_POST_ISR);

}

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) {

return (OS_ERR_PEVENT_NULL);

}

if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

pip = (INT8U)(pevent->OSEventCnt >> 8);

prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);

if (OSTCBCur->OSTCBPrio != pip &&OSTCBCur->OSTCBPrio != prio) { OS_EXIT_CRITICAL();

return (OS_ERR_NOT_MUTEX_OWNER);

}

if (OSTCBCur->OSTCBPrio == pip) {

if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) ==0)

{

OSRdyGrp &= ~OSTCBCur->OSTCBBitY;

}

OSTCBCur->OSTCBPrio = prio;

OSTCBCur->OSTCBY = prio >> 3;

OSTCBCur->OSTCBBitY = OSMapTbl[OSTCBCur->OSTCBY];

OSTCBCur->OSTCBX = prio & 0x07;

OSTCBCur->OSTCBBitX = OSMapTbl[OSTCBCur->OSTCBX];

OSRdyGrp |= OSTCBCur->OSTCBBitY;

OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;

OSTCBPrioTbl[prio] = (OS_TCB *)OSTCBCur;

}

OSTCBPrioTbl[pip] = (OS_TCB *)1;

if (pevent->OSEventGrp != 0x00) { prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);

pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;

pevent->OSEventCnt |= prio;

pevent->OSEventPtr = OSTCBPrioTbl[prio];

OS_EXIT_CRITICAL();

OS_Sched();

return (OS_NO_ERR);

}

pevent->OSEventCnt |= OS_MUTEX_AVAILABLE;

pevent->OSEventPtr = (void *)0;

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

8.04 无等待地获取互斥型信号量, OSMutexAccept()

#if OS_MUTEX_ACCEPT_EN > 0

INT8U OSMutexAccept (OS_EVENT *pevent, INT8U *err) {

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR cpu_sr;

#endif

if (OSIntNesting > 0) {

*err = OS_ERR_PEND_ISR;

return (0);

}

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) {

*err = OS_ERR_PEVENT_NULL;

return (0);

}

if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { *err = OS_ERR_EVENT_TYPE;

return (0);

}

#endif

OS_ENTER_CRITICAL();

if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_A V AILABLE) {

pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;

pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;

pevent->OSEventPtr=(void*)OSTCBCur;

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return (1);

}

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return (0);

}

#endif

8.05获取互斥型信号量的当前状态, OSMutexQuery()

#if OS_MUTEX_QUERY_EN > 0

INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata) {

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR cpu_sr;

#endif

INT8U *psrc;

INT8U *pdest;

if (OSIntNesting > 0) {

return (OS_ERR_QUERY_ISR);

}

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) {

return (OS_ERR_PEVENT_NULL);

}

if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

pdata->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8);

pdata->OSOwnerPrio=(INT8U)(pevent->OSEventCnt&

OS_MUTEX_KEEP_LOWER_8);

if (pdata->OSOwnerPrio == 0xFF) {

pdata->OSValue = 1;

} else {

pdata->OSValue = 0;

}

pdata->OSEventGrp = pevent->OSEventGrp;

psrc = &pevent->OSEventTbl[0];

pdest = &pdata->OSEventTbl[0];

#if OS_EVENT_TBL_SIZE > 0

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 1

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 2

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 3

*pdest++ = *psrc++; #endif

#if OS_EVENT_TBL_SIZE > 4

*pdest++ = *psrc++; #endif

#if OS_EVENT_TBL_SIZE > 5

*pdest++ = *psrc++; #endif

#if OS_EVENT_TBL_SIZE > 6

*pdest++ = *psrc++; #endif

#if OS_EVENT_TBL_SIZE > 7

*pdest = *psrc;

#endif

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

#endif

用信号量实现线程同步与互斥

用信号量实现线程同步与互斥 一、相关Win32 API函数 1、创建线程 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); 函数作用:在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄。 各参数含义: ?lpThreadAttributes:指向一个SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为NULL; ?dwStackSize:指定了线程的堆栈深度,一般都设置为0; ?lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。 一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是线程函数 名;函数名称没有限制,但是必须以下列形式声明:DWORD WINAPI ThreadProc (PVOID pParam) ; ?lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数; ?dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产 生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用; ?lpThreadId:该参数返回所创建线程的ID。 如果创建成功则返回线程的句柄,否则返回NULL。 例如: for (int i=0;i

1-3章习题(附答案)

OS 1-3章习题 3.操作系统是一种(A),它负责为用户和用户程序完成所有(B)的工作,(C)不是操作系统关心的主要问题。 A:(1)应用软件;(2)系统软件;(3)通用软件;(4)软件包。 B:(1)与硬件无关并与应用无关;(2)与硬件相关而与应用无关;(3)与硬件无关而与应用相关;(4)与硬件相关并与应用相关。 C:(1)管理计算机裸机;(2)设计、提供用户程序与计算机硬件系统的接口;(3)管理计算机中的信息资源;(4)高级程序设计语言的编译。 4.在OS总采用多道程序设计技术,能有效地提高CPU、内存和I/O设备的(A)。为实现多道程序设计需要有(B)。 A:(1)灵活性;(2)可靠性;(3)兼容性;(4)利用率。 B:(1)更大的内存;(2)更快的CPU;(3)更快的外部设备;(4)更先进的终端。 5.推动批处理系统形成和发展的主要动力是(A),推动分时系统形成和发展的主要动力是(B),推动微机OS发展的主要动力是(C)。 A,B:(1)提高计算机系统的功能;(2)提高系统资源利用率-A;(3)方便用户-B;(4)提高系统的运行速度。 C:(1)方便用户;(2)计算机硬件的不断更新换代;(3)便于微机联网;(4)提高资源的利用率。 6.在设计分时操作系统时,首先要考虑的是(A);在设计批处理操作系统时,首先要考虑的是(B);在设计实时操作系统时,首先要考虑的是(C)。 A,B,C:(1)灵活性和可适应性;(2)交互性和响应时间-A;(3)周转时间和系统吞吐量-B;(4)实时性和可靠性-C。 7.在多道批处理系统中,为了充分利用各种资源,系统总是优先选择(A)多个作业投入运行;为了提高吞吐量,系统总是想方设法缩短用户作业的(B)。 A:(1)适应于内存容量的;(2)计算量大的;(3)I/O量大的;(4)计算型和I/O型均衡的。 B:(1)周转时间;(2)运行时间;(3)提交时间;(4)阻塞时间。

信号量互斥题目

试用用信号量机制描述两人下象棋的过程。 两人下象棋的过程可以概括为:一开始只能是“红先黑后”,以后两人要循环轮流走子,直至某一方获胜或双方和棋为

止。? 这是个只有一个生产者和一个消费者的生产者——消费者问题,是个典型的“你等我,我也等你”的问题。红方是总的前趋任务——生产者进程,黑方是总的后继任务——消费者进程,但由于下棋过程必须轮流走子,所以红黑双方的生产者消费者身份会轮流改变。棋盘则是生产者与消费者共享的缓冲。?要求:只描述对弈过程,对棋盘的访问不做描述。二人对弈过程是个纯粹的同步过程 ①所用信号量设臵如下: Ⅰ)同步信号量hei,初值为1,表示黑方已走子,开始时可使红方先行不受阻。 Ⅱ)同步信号量hong,初值为0,表示红方尚未走子,开始时可使黑方先行受阻。 用信号量机制描述的二人下象棋过程如下

有一个阅览室,共有100个座位,读者进入时必须先在一张登记表上登记,该表为每一座位列一表目,包括座号和读者姓名等,读者离开时要消掉登记的信息,试问: (1)为描述读者的动作,应编写几个程序,设臵几个进程?(2)试用P、V操作描述读者进程之间的同步关系。分析:?读者的动作都是一样的:登记进入阅览室,阅读, 撤消登记离开阅览室,因此可写一个程序,设n个进程。 ?读者共享的资源有阅览室的座位和登记表,因此诸 个读者进程之间有两种互斥制约关系,需设2个信号量来实现:? seat:用于实现诸读者对阅览室的空闲座位的互斥 竞争,初值为100; ? mutex:用于实现诸读者对登记表的互斥访问,初值 为1

(1)可写一个程序,设n个进程 (2)读者进程readeri(i=1,2,3,……)描述如下: P(seat); /*申请空座位*/ P(mutex); /*申请登记*/ 登记; V(mutex) /*允许其他读者登记*/ 阅读; P(mutex); /*申请撤消登记*/ 撤消登记; V(mutex); /*允许其他读者撤消登记*/ V(seat); /*释放座位,允许他人进入*/

1互斥信号量:

1.互斥信号量: 互斥互斥,意思就是我用了你就不能用,你用了我就不能用。永远都只有一个人独占这个东西~!举个例子:比如说打印机。 我任务1现在让他打印《静夜思》,那么在我还没打印完之前,别的任务就不能命令打印机去打印别的东西。否则如果任务2让他打印《春晓》,那最后打印出来的会是什么~????反正肯定不是任务1想要的,肯定也不是任务2想要的。 上面讲的比较通俗。打印机就是共享资源,谁都可以访问他~!但是同一时间,肯定要保证只有1个任务再操作打印机。那样才能得到大家想要的结果。也就是要独占共享资源的访问权~! ucos2中通过互斥信号量来解决这个问题。简单说就是任务1开始访问打印机的时候,先去查询这个互斥信号量是否有效,有效,说明没人在访问打印机,这时任务1就把这个互斥信号量置无效,然后开始操作打印机。这样,每个任务再操作打印机前都要去查询这个互斥信号量时候有效。无效就等,等到有效才可以访问,或者等到不耐烦了(术语叫等待超时)就不等了~!任务一直到用完了打印机后才把信号量置有效,这时其他任务才有可能去访问,操作打印机。 这里又有一个问题:再任务1操作打印机器件,可能有多个任务申请打印机的所有权。那么再任务1结束后,我应该给谁用呢~~??也许我们马上就反应过来了~废话~!!当然是排队了~~谁先到的谁用啊~~~。没错,这是一种机制,谁最先等待共享资源,就给谁用。但是~!再ucos里面2.52版本还不支持这种方式。他用的另外一种方法!如果你和你BOSS都再等着用打印机,你先到的,这个时候任务1结束了对打印机的操作。你说你敢先用么~???(除非你第二天不想干了~~)你肯定先让老板先用,这就是ucos的实现方式,基于优先级,任务1结束对打印机的操作后,ucos再等待队列中看那个等待任务优先级最高,就先给他用~!即使他是最晚才等待的~!!(这就是BOSS的威力~!) 关于事件等待列表,有兴趣的可以去看看事件控制块ECB的内容,不在本文讨论。当然,ucos中的互斥信号量还有许多要素,比如说他的继承优先级之类的。本文旨在说明它是干嘛用的,至于其他请参考相关书籍。 下面的图解释了互斥信号量的基本用法:(简单的两个任务,没有包含多任务等待的情况)

实验八 uCOS-II的互斥信号量

实验八uCOS的互斥信号量 一:实验目的: 1.理解互斥型信号量。 2.学会使用互斥型信号量实现对共享资源的独占式处理。 3.解决任务在使用独占式资源出现的优先级反转问题。 二:实验内容: 完成教材5-7实验,使用互斥型信号量实现对共享资源的独占式处理。实验中要求要创建互斥型信号量,请求互斥型信号量,发送互斥型信号量,删除互斥型信号量。 三:程序代码: #include "includes.h" #define TASK_STK_SIZE 512 OS_STK StartTaskStk[TASK_STK_SIZE]; OS_STK MyTaskStk[TASK_STK_SIZE]; OS_STK YouTaskStk[TASK_STK_SIZE]; OS_STK HerTaskStk[TASK_STK_SIZE]; INT16S key; char *s1="MyTask running--yangkun"; char *s2="YouTask running--yangkun"; char *s3="HerTask running--yangkun"; char *s4="MyTask pend_Semp"; char *s5="HerTask pend_Semp"; INT8U err; INT8U y=0; INT32U Times=0; OS_EVENT *Semp; void StartTask(void *pdata); void MyTask(void *pdata); void YouTask(void *pdata); void HerTask(void *pdata); void main (void) { OSInit();

uCOS-II互斥信号量

μCOS-II互斥信号量 Application Note AN-1002 Jean J. Labrosse https://www.360docs.net/doc/5c5610250.html,brosse@https://www.360docs.net/doc/5c5610250.html, https://www.360docs.net/doc/5c5610250.html, 概述: 使用互斥信号(Mutual Exclusion Semaphores)或者简单的互斥(mutexes)实现对资源的独占访问,互斥信号本身是一种二进制信号,具有超出μCOS-II提供的一般信号机制的特性。本手册描述了C/OS-II V2.04增加的mutex一系列服务。 简介: 在应用程序中使用互斥信号是为了减少优先级翻转问题(priority inversion problem),如μC/OS-II, The Real-Time kernel (ISBN 0-87930-543-6), section 2.16, page 47中描述的。 当一个高优先级的任务需要的资源被一个低优先级的任务使用是,就会发生优先级翻转问题。为了减少优先级翻转问题,内核可以提高低优先级任务的优先级,先于高优先级的任务运行,释放占用的资源。 为了实现互斥,实时内核需要具有支持在同一优先级具有多个任务的能力。不幸的是,μC/OS-II不允许在相同的优先级有多个任务,必须只有一个任务。但是我们有另外的方法解决这个问题。可以把需要资源的高优先级任务上面的一个任务使用Mutex保留,允许提高低优先级任务的优先级。 举一个mutexes信号工作的例子,如listing1所示。 Listing 1中有三个任务可以使用共同的资源,为了访问这个资源,每个任务必须在互斥信号ResourceMutex上等待(pend),任务#1有最高优先级10,任务#2优先级为15,任务#3优先级为20,一个没有使用的正好在最高优先级之上的优先级#9用来作为优先级继承优先级(Priority Inheritance Priority-PIP)。如main()所示,L1(1)进行μC/OS-II初始化,并通过调用OSMutexCreate() L1(2)创建了一个互斥信号。需要注意的是,OSMutexCreate()函数使用PIP最为参数。然后创建三个任务L1(3),启动μC/OS-II L1(4). 假设任务运行了一段时间,在某个时间点,任务#3最先访问了共同的资源,并得到了互斥信号,任务#3运行了一段时间后被任务#1抢占。任务#1需要使用这个资源,并通过调用OSMutexPend()企图获得互斥信号,这种情况下,OSMutexPend()会发现一个高优先级的任务需要这个资源,就会把任务#3的优先级提高到9,同时强迫进行上下文切换退回到任务#3执行。任务#3可以继续执行然后释放占用的共同资源。任务#3通过调用OSMutexPost()释放占用的mutex信号,OSMutexPost()会发现mutex被一个优先级提升的低优先级的任务占有,就会把任务#3的优先级返回到20。把资源释放给任务#1使用,执行上下文切换到任务#1

操作系统信号量PV操作题若干

(一)图书馆有100个座位,每位进入图书馆的读者要在登记表上登记,退出时要在登记表上注销。要几个程序?有多少个进程?(答:一个程序;为每个读者设一个进程) (1)当图书馆中没有座位时,后到的读者在图书馆为等待(阻塞) (2)当图书馆中没有座位时,后到的读者不等待,立即回家。 设信号量S=200;MUTEX=1; P(S) P(MUTEX) 登记 V(MUTEX) 阅读 P(MUTEX) 注销 V(MUTEX) V(S) (2) 设信号量MUTEX=1; 整型变量S=200; P(MUTEX) IF(S==0) { V(MUTEX) RETURN } ELSE{ COUNT=COUNT-1; 登记 V(MUTEX) 阅读 P(MUTEX) COUNT=COUNT+1; 注销 V(MUTEX) RETURN }

解(1 ) 设信号量:S=100; MUTEX=1 P(S) P(MUTEX) 登记 V(MUTEX) 阅读 P(MUTEX) 注销 V(MUTEX) V(S) 解(2) 设整型变量COUNT=100; 信号量:MUTEX=1; P(MUTEX); IF (COUNT==0) { V(MUTEX); RETURN; } COUNT=COUNT-1; 登记 V(MUTEX); 阅读 P(MUTEX); COUNT=COUNT+1; V(MUTEX); RETURN;

(二)有一座东西方向的独木桥;用P,V操作实现: (1)每次只允许一个人过桥; (2)当独木桥上有行人时,同方向的行人可以同时过桥,相反方向的人必须等待。(3)当独木桥上有自东向西的行人时,同方向的行人可以同时过桥,从西向东的方向,只允许一个人单独过桥。(此问题和读者与写者问题相同,东向西的为读者,西向东的为写者)。 (1) 设信号量S=1 P(S) 过桥 V(S) (2) 设信号量S=1 EW=1;(东向西互斥计数量) WE=1;(西向东互斥计数量) 整型变量 CE =0;(东向西桥上人数) CW=0;(西向东桥上人数) 东向西: P(EW) IF(CE==0) { P(S) } CE++; V(EW) 过桥 P(EW) CD--; IF(CD==0){ V(S) } V(EW)

临界区,互斥量,信号量,事件的区别

四种进程或线程同步互斥的控制方法 1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。 2、互斥量:为协调共同对一个共享资源的单独访问而设计的。 3、信号量:为控制一个具有有限数量用户资源而设计。 4、事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。 临界区(Critical Section) 保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。 临界区包含两个操作原语: EnterCriticalSection()进入临界区 LeaveCriticalSection()离开临界区 EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。 MFC提供了很多功能完备的类,我用MFC实现了临界区。MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是非常简单的。只需在线程函数中用CCriticalSection类成员函数Lock()和UnLock()标定出被保护代码片段即可。Lock()后代码用到的资源自动被视为临界区内的资源被保护。UnLock后别的线程才能访问这些资源。 互斥量(Mutex) 互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。互斥量比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。 互斥量包含的几个操作原语: CreateMutex()创建一个互斥量 OpenMutex()打开一个互斥量 ReleaseMutex()释放互斥量 WaitForMultipleObjects()等待互斥量对象 同样MFC为互斥量提供有一个CMutex类。使用CMutex类实现互斥量操作非常简单,但是要特别注意对CMutex的构造函数的调用 CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL) 不用的参数不能乱填,乱填会出现一些意想不到的运行结果。 信号量(Semaphores)

经典PV操作讲解和练习题

在计算机操作系统中,PV操作是进程管理中的难点。 首先应弄清PV操作的含义:PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下: P(S):①将信号量S的值减1,即S=S-1; ②如果S30,则该进程继续执行;否则该进程置为等待状态,排入等待队列。 V(S):①将信号量S的值加1,即S=S+1; ②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。 PV操作的意义:我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。 什么是信号量?信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。 一般来说,信号量S30时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S 的值加1;若S£0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。 利用信号量和PV操作实现进程互斥的一般模型是: 进程P1 进程P2 ……进程Pn ……………… P(S); P(S); P(S); 临界区;临界区;临界区; V(S); V(S); V(S); …………………… 其中信号量S用于互斥,初值为1。 使用PV操作实现进程互斥时应该注意的是: (1)每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。 (2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。(3)互斥信号量的初值一般为1。 利用信号量和PV操作实现进程同步 PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。 使用PV操作实现进程同步时应该注意的是: (1)分析进程间的制约关系,确定信号量种类。在保持进程间有正确的同步关系情况下,哪个进程先执行,哪些进程后执行,彼此间通过什么资源(信号量)进行协调,从而明确要设置哪些信号量。

同步和互斥的区别_

同步和互斥的区别

信号量互斥量条件变量 同步和互斥 一、信号量:用于进程间通信(linux中用于线程) 独立于进程在两个进程中都要初始化,若一个已创建,则另一个获取可以执行多次v操作,然后再执行p操作 信号量的一些概念: 以下是信号灯(量)的一些概念: 信号灯与互斥锁和条件变量的主要不同在于”灯”的概念,灯亮则意味着资源可用,灯灭则意味着不可用。如果说后两中同步方式侧重于”等待”操作,即资源不可用的话,信号灯机制则侧重于点灯,即告知资源可用;没有等待线程的解锁或激发条件都是没有意义的,而没有等待灯亮的线程的点灯操作则有效,且能保持灯亮状态。当然,这样的操作原语也意味着更多的开销。 信号灯的应用除了灯亮/灯灭这种二元灯以外,也可以采用大于1的灯数,以表示资源数大于1,这时可以称之为多元灯。 二、互斥量:(用于在线程间的通信) 1、在一个进程中创建 三、信号量与互斥量的区别 1. 互斥量用于线程的互斥,信号量用于线程的同步。 这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源 以上区别是主要想记住的。 note:信号量可以用来实现互斥量的功能 2. 互斥量值只能为0/1,信号量值可以为非负整数。 也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成一个资源的互斥访问。3、互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。 4、作用域 信号量: 进程间或线程间(linux仅线程间) 互斥锁: 线程间 5、上锁时 信号量: 只要信号量的value大于0,其他线程就可以sem_wait(p操作-1)成功,成功后信号量的value减一。若value值不大于0,则

操作系统-进程同步-信号量练习题

1【单选题】用P、V操作管理临界区时,互斥信号量的初值应定义为( A)。 ?A,1 ?B,0 ?C,-1 ?D,任意值 2【单选题】在操作系统中,对信号量S的P原语操作定义中,使进程进入相应等待队列等待的条件是( )。 ?A,S>0 ?B,S = 0 ?C,S<0 ?D,S<>0 我的答案:C 3【单选题】信号量S的初值为8,在S上执行了10次wait 操作,6次signal操作后,S的值为(D )。 ?A,10 ?B,8 ?C,6 ?D,4 P操作每执行一次,信号量减1;V操作每执行一次,信号量加1.所以答案为8-10+6 = 4

4【单选题】用V操作唤醒一个等待进程时,被唤醒进程的状态应变成( B)状态。 ?A,执行 ?B,就绪 ?C,阻塞 ?D,挂起 被唤醒的进程由等待状态变为就绪状态。 5【单选题】利用Wait和signal操作可以( )。 ?A,实现进程互斥和同步 ?B,检测死锁 ?C,解除死锁 ?D,防止死锁 我的答案:A 6【单选题】两个并发进程,设互斥信号量mutex(初值为1),若信号量=0;则(B ) ?A,表示没有进程进入临界区 ?B,表示有一个进程进入临界区 ?C,表示有一个进程进入临界区,另一个进程等待进入 ?D,表示两个进程进入临界区 临界区不允许两个进程同时进入,D选项明显错误。mutex初值为1,表示允许一个进程进入临界区,当有一个进程进入临界区且没有进程等待进入时,mutex值减1,变为0。

7【单选题】V操作是对信号量执行加1操作,意味着释放一个单位资源,加1后如果信号量的值等于零,则从等待队列中唤醒一个进程,现进程变为等待状态,否则现进程继续进行。?A,对 ?B,错 我的答案:B 8【单选题】有3个进程,两台打印机,用wait和sigual操作来实现互斥访问打印机,则信号量S的取值范围是( ) ?A,2,1,0,-1 ?B,3,2,1,0 ?C,2,1,0,-1,-2 ?D,1,0,-1,-2 我的答案:如果n个进程共享两个打印机,信号量取值范围:-(n-2)~2; 9【单选题】设与某资源相关的资源信号量K,初值为3,当前值为1,则可用资源个数为( ),等待资源的进程数为( )。 ?A,0,1 ?B,1,0 ?C,1,2 ?D,2,0 我的答案:B

第8章 互斥信号量管理

第8章互斥型信号量管理 任务可以用互斥型信号量实现对共享资源的独占式处理。mutex是二值信号量。 mutex可以在应用程序中用于降解优先级反转问题。 互斥型信号量由3个元素组成: 1个标志,指示mutex是否可以使用(0或1); 1个优先级,准备一旦高优先级的任务需要这个mutex,赋给占有mutex的任务; 1个等待该mutex的任务列表。 对于互斥型信号量提供6种服务:OSMutexCreate(),OSMutexDel(),OSMutexPend(),OSMutexPost(),OSMutexAccept(),OSMutexQuery()。 mutex只能供任务使用,用于处理共享资源。 8.00 建立一个互斥型信号量, OSMutexCreate() 程序清单 L8.2建立一个信号量 OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err) { #if OS_CRITICAL_METHOD == 3 OS_CPU_SR cpu_sr; #endif OS_EVENT *pevent; if (OSIntNesting > 0) { *err = OS_ERR_CREATE_ISR; return ((OS_EVENT *)0); } #if OS_ARG_CHK_EN > 0 if (prio >= OS_LOWEST_PRIO) { *err = OS_PRIO_INVALID; return ((OS_EVENT *)0); } #endif OS_ENTER_CRITICAL(); if (OSTCBPrioTbl[prio] != (OS_TCB *)0) {

计算机操作系统练习题及答案

单项选择 1. 两个进程合作完成一项任务。在并发执行中,一个进程要等待其合作伙伴发来消息,或建立某个条件后再运行,这种制约性合作关系被称为进程的—A—。 A.同步 B.执行 C.互斥 D.调度 2. 为了进行进程协调,进程之间应当具有一定的联系,这种联系通常采用进程间交换数据的方式进行,这种方式通常称为—C—。 A. 进程互斥 B. 进程同步 C. 进程通信 D. 进程制约 3. 除了因为资源不足,进程竞争资源可能出现死锁外,不适当的—C—也可能产生死锁。 A.进程优先权 B.资源线性分配 C.进程推进顺序 D.分配队列优先权 4. 除了可以采用资源剥夺法解除死锁外,还可以采用—C—方法解除死锁。 A.修改信号量 B.拒绝分配新的资源 C.撤消进程 D.执行并行操作 5. 资源的按序分配策略可以破坏—D—条件。 A. 互斥 B. 请求与保持 C. 不剥夺 D. 环路等待 6. 在—C—的情况下,系统出现死锁。 A. 计算机系统发生了重大故障 B. 有多个阻塞的进程存在 C. 若干个进程因竞争资源而无休止地相互等待他方释放已占有的资源 D. 资源数远小于进程数或进程同时申请的资源数远超过资源总数 7.某系统中有3个进程,都需要同类资源4个,试问该系统不会发生死锁的最少资源数是—B—。 A.9 B.10 C.11 D.12 8. 银行家算法是一种—B—算法。 A. 解除死锁 B.避免死锁 C. 预防死锁 D. 检测死锁 9. 在下列解决死锁的方法中,属于死锁预防策略的是—B—。 A. 银行家算法 B. 资源有序分配 C. 死锁检测法 D. 资源分配图化简法 10. 设有n个进程共用一个相同的程序段(临界区),如果每次最多允许m个进程(m≤n)同时进入临界区,则信号量的初值应为—B—。 A. n B. m C. m-n D. -m 11.死锁定理是用于处理死锁的哪一种方法—C—。 A.预防死锁 B.避免死锁 C.检测死锁 D.解除死锁 12. AND信号量集机制是为了—C—。 A. 信号量的集中使用 B. 解决结果的不可再现性问题 C. 防止系统的不安全性 D. 实现进程的相互制约 13.临界区是指—A—。

同步和互斥的区别

信号量互斥量条件变量 同步和互斥 一、信号量:用于进程间通信(linux中用于线程) 独立于进程在两个进程中都要初始化,若一个已创建,则另一个获取可以执行多次v操作,然后再执行p操作 信号量的一些概念: 以下是信号灯(量)的一些概念: 信号灯与互斥锁和条件变量的主要不同在于”灯”的概念,灯亮则意味着资源可用,灯灭则意味着不可用。如果说后两中同步方式侧重于”等待”操作,即资源不可用的话,信号灯机制则侧重于点灯,即告知资源可用;没有等待线程的解锁或激发条件都是没有意义的,而没有等待灯亮的线程的点灯操作则有效,且能保持灯亮状态。当然,这样的操作原语也意味着更多的开销。 信号灯的应用除了灯亮/灯灭这种二元灯以外,也可以采用大于1的灯数,以表示资源数大于1,这时可以称之为多元灯。 二、互斥量:(用于在线程间的通信) 1、在一个进程中创建 三、信号量与互斥量的区别 1. 互斥量用于线程的互斥,信号量用于线程的同步。 这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源 以上区别是主要想记住的。 note:信号量可以用来实现互斥量的功能 2. 互斥量值只能为0/1,信号量值可以为非负整数。 也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成一个资源的互斥访问。3、互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。 4、作用域 信号量: 进程间或线程间(linux仅线程间) 互斥锁: 线程间 5、上锁时 信号量: 只要信号量的value大于0,其他线程就可以sem_wait(p操作-1)成功,成功后信号量的value减一。若value值不大于0,则sem_wait

信号量机制与互斥的加锁实现的优缺点比较

互斥的加锁实现与信号量机制的优缺点对比 (一)互斥的加锁实现 当某个进程进入临界区之后,临界区将被上锁,直到它退出临界区为止。并发进程在申请进入临界区之前,首先测试该临界区是否是上锁的。如果是上锁的,则要等到开锁以后才有可能活的临界区。 设临界区类名为S,锁定位key【S】。 加锁后临界区程序描述如下: Lock(key【S】) <临界区> Unlock(key【S】) 设key【S】=1时表示该临界区可用,key【S】=0时表示该临界区不可用。则unlock(key 【S】)只用一条语句即可实现。即: Key【S】<—1 不过由于lock(key【S】)必须满足key【S】=0时,不允许任何进程进入临界区,而key 【S】=1时仅允许一个进程进入临界区的准则,因而实现起来较为困难。仍存在一些影响系统可靠性和执行效率的问题,例如循环测试定位将消耗较多的cpu计算时间等等。还会导致一些不公平现象。每个进程能否进入临界区是依靠自己的测试判断。这样,没有获得执行机会的进程当然没法判断,从而产生某进程处于永久饥饿状态。 (二)信号量机制 信号量sem是一整数。在sem大于等于零时代表可供并发进程使用的资源实体数,但sem小于零时则表示正在等待实用临界区的进程数。显然,对于互斥的信号量sem初值应该大于零。 P,V原语操作能改变信号量的数值,信号量(sem)可代表管理相应临界区公共资源的实体。而一次P操作使得sem减1,一次V操作使得sem加1。 P,V操作中进程不需要象加锁时要不断的测试,而是在队列里等待其他进程执行V操作时,就可以进入临界区了。这样P,V操作比加锁更简单,且表达能力强,但P,V相对来说不安全,会出现死锁,遇到复杂的同步互斥问题时会更复杂。

计算机操作系统习题及答案(4)

第4章进程同步与通信 1)选择题 (1)在操作系统中,P、V操作是一种_D__。 A. 机器指令 B. 系统调用命令 C. 作业控制命令 D. 低级进程通信原语 (2)若信号量S的初值为2,当前值为-1,则表示有_B__等待进程。 A. 0个 B. l个 C. 2个 D. 3个 (3)在直接通信方式中,系统提供两条通信原语进行发送和接收,其中Send原语中参数应是_C_。 A. sender,message B. sender,mailbox C. receiver,message D. receiver,mailbox (4)下述那个选项不是管程的组成部分_A__。 A. 管程外过程调用管程内数据结构的说明 B. 管程内对数据结构进行操作的一组过程 C. 局部于管程的共享数据说明 D. 对局部于管程的数据结构设置初值的语句 (5)某通信方式通过共享存储区来实现,其属于_D__。 A. 消息通信 B. 低级通信 C. 管道通信 D. 高级通信 (6)用P、V操作管理临界区时,信号量的初值应定义为__C__。 A. -1 B. 0 C. 1 D. 任意值 (7)临界区是_B__。 A. 一个缓冲区 B. 一段程序 C. 一段共享数据区 D. 一个互斥资源 (8)信箱通信是一种_D__通信方式。 A. 直接通信 B. 信号量 C. 低级通信 D. 间接通信 (9)对于两个并发进程,设互斥信号量为mutex,若mutex=0则__A_。 A. 表示有一个进程进入临界区 B. 表示没有进程进入临界区 C. 表示有一个进程进入临界区,另一个进程等待进入 D. 表示有两个进程进入临界区 (10)对信号量S执行V操作后,下述选项正确的是_C__。

信号量 互斥锁 条件变量的区别

信号量互斥锁条件变量的区别(这是我在网上找到的一个解释,个人认为讲的很好,供同学们参考一下,如果看不懂可以与我交流) 信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在哪里)。而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这个资源。比如对全局变量的访问,有时要加锁,操作完了,在解锁。有的时候锁和信号量会同时使用的” 也就是说,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤,这个任务并不一定是锁定某一资源,还可以是进行一些计算或者数据处理之类。而线程互斥量则是“锁住某一资源”的概念,在锁定期间内,其他线程无法对被保护的数据进行操作。在有些情况下两者可以互换。 两者之间的区别: 作用域 信号量: 进程间或线程间(linux仅线程间) 互斥锁: 线程间 上锁时 信号量: 只要信号量的value大于0,其他线程就可以sem_wait成功,成功后信号量的value 减一。若value值不大于0,则sem_wait阻塞,直到sem_post释放后value值加一 互斥锁: 只要被锁住,其他任何线程都不可以访问被保护的资源 成功后否则就阻塞 以下是信号灯(量)的一些概念: 信号灯与互斥锁和条件变量的主要不同在于”灯”的概念,灯亮则意味着资源可用,灯灭则意味着不可用。如果说后两中同步方式侧重于”等待”操作,即资源不可用的话,信号灯机制则侧重于点灯,即告知资源可用;没有等待线程的解锁或激发条件都是没有意义的,而没有等待灯亮的线程的点灯操作则有效,且能保持灯亮状态。当然,这样的操作原语也意味着更多的开销。 信号灯的应用除了灯亮/灯灭这种二元灯以外,也可以采用大于1的灯数,以表示资源数大于1,这时可以称之为多元灯。 1.创建和注销 POSIX信号灯标准定义了有名信号灯和无名信号灯两种,但LinuxThreads的实现仅有无名灯,同时有名灯除了总是可用于多进程之间以外,在使用上与无名灯并没有很大的区别,因此下面仅就无名灯进行讨论。

ucosii对于信号量,互斥信号量,事件标志组的个人理解

ucosii对于信号量,互斥信号量,事件标志组的个人理解 ucos看了也有一周多了,索性源码都能开得懂,并且能去理解。昨天一开始看事件标志组 的时候确实不知道怎么回事,后来百度一下,明白了事件标志组的作用以后,再去看书上的讲解和原码就清晰多了,很容易就明白了他的基本运行机理。这也给了我一点启示,学一个东西,看一个东西之前,你最少要知道他干嘛用的,如果连干嘛用的都知道书看的再熟也是枉然。 ucos中提供了好几个用于同步事件以及共享资源访问的机制,目前我看明白的有信号量,互斥信号量,事件标志组。下面谈谈自己对他们的理解: 1.互斥信号量: 互斥互斥,意思就是我用了你就不能用,你用了我就不能用。永远都只有一个人独占这个东西~!举个例子:比如说打印机。 我任务1现在让他打印《静夜思》,那么在我还没打印完之前,别的任务就不能命令打印机去打印别的东西。否则如果任务2让他打印《春晓》,那最后打印出来的会是什么~????反正肯定不是任务1想要的,肯定也不是任务2想要的。 上面讲的比较通俗。打印机就是共享资源,谁都可以访问他~!但是同一时间,肯定要保证只有1个任务再操作打印机。那样才能得到大家想要的结果。也就是要独占共享资源的访问权~! ucos2中通过互斥信号量来解决这个问题。简单说就是任务1开始访问打印机的时候,先去查询这个互斥信号量是否有效,有效,说明没人在访问打印机,这时任务1就把这个互斥信号量置无效,然后开始操作打印机。这样,每个任务再操作打印机前都要去查询这个互斥信号量时候有效。无效就等,等到有效才可以访问,或者等到不耐烦了(术语叫等待超时)就不等了~!任务一直到用完了打印机后才把信号量置有效,这时其他任务才有可能去访问,操作打印机。 这里又有一个问题:再任务1操作打印机器件,可能有多个任务申请打印机的所有权。那么再任务1结束后,我应该给谁用呢~~??也许我们马上就反应过来了~废话~!!当然是排 队了~~谁先到的谁用啊~~~。没错,这是一种机制,谁最先等待共享资源,就给谁用。但是~!再ucos里面2.52版本还不支持这种方式。他用的另外一种方法!如果你和你BOSS都 再等着用打印机,你先到的,这个时候任务1结束了对打印机的操作。你说你敢先用么~???(除非你第二天不想干了~~)你肯定先让老板先用,这就是ucos的实现方式,基于优先级,任务1结束对打印机的操作后,ucos再等待队列中看那个等待任务优先级最高,就先给他 用~!即使他是最晚才等待的~!!(这就是BOSS的威力~!) 关于事件等待列表,有兴趣的可以去看看事件控制块ECB的内容,不在本文讨论。当然,

互斥量、临界区、信号量和时间的作用与区别

互斥量、临界区、信号量和时间的作用与区别 不管是辅助线程还是用户接口线程,在存取共享资源时,都需要保护共享资源,以免引起冲突,造成错误。处理方法类似于Win32 API函数的使用,但MFC为我们提供了几个同步对象C++类,即CSyncObject、CMutex、CSemaphore、CEvent、CCriticalSection。这里,CSyncObject为其它四个类的基类,后四个类分别对应前面所讲的四个Win32 API同步对象。 通常,我们在C++对象的成员函数中使用共享资源,或者把共享资源封装在C++类的内部。我们可将线程同步操作封装在对象类的实现函数当中,这样在应用中的线程使用C++对象时,就可以像一般对象一样使用它,简化了使用部分代码的编写,这正是面向对象编程的思想。这样编写的类被称作"线程安全类"。在设计线程安全类时,首先应根据具体情况在类中加入一个同步对象类数据成员。然后,在类的成员函数中,凡是所有修改公共数据或者读取公共数据的地方均要加入相应的同步调用。一般的处理步骤是:创建一个CSingleLock或者CMultiLock对象,然后调用其Lock函数。当对象结束时,自动在析构函数中调用Unlock函数,当然也可以在任何希望的地方调用Unlock函数。 如果不是在特定的C++对象中使用共享资源,而是在特定的函数中使用共享资源(这样的函数称为"线程安全函数"),那么还是按照前面介绍的办法去做:先建立同步对象,然后调用等待函数,直到可以访问资源,最后释放对同步对象的控制。 下面我们讨论四个同步对象分别适用的场合: (1)如果某个线程必须等待某些事件发生后才能存取相应资源,则用CEvent; (2)如果一个应用同时可以有多个线程存取相应资源,则用CSemaphore; (3)如果有多个应用(多个进程)同时存取相应资源,则用CMutex,否则用CCriticalSection。 使用线程安全类或者线程安全函数进行编程,比不考虑线程安全的编程要复杂,尤其在进行调试时情况更为复杂,我们必须灵活使用Visual C++提供的调试工具,以保证共享资源的安全存取。线程安全编程的另一缺点是运行效率相对要低些,即使在单个线程运行的情况下也会损失一些效率。所以,我们在实际工作中应具体问题具体分析,以选择合适的编程方法。 OS中的解说及详细编程使用: 1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。 2.互斥量:为协调共同对一个共享资源的单独访问而设计的。 3.信号量:为控制一个具有有限数量用户资源而设计。 4.事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。 临界区(Critical Section) 保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临

相关文档
最新文档