信号量详解
- 格式:doc
- 大小:71.50 KB
- 文档页数:8
试述信号量及其物理含义
信号量是一种在操作系统和并发编程中用于控制对共享资源的访问的机制。
它可以用来跟
踪和控制对临界区的访问,并防止多个进程或线程同时访问同一个资源。
信号量的物理含义可以类比为一个计数器。
假设有一个资源只能同时被一个进程或线程访问,
那么信号量初始值为1。
当一个进程或线程想要访问这个资源时,它会将信号量减少1。
如果
信号量的值变为了0,那么表示资源正在被占用,其他进程或线程需要等待。
当占用资源的进
程或线程完成任务后,会将信号量增加1,然后等待的进程或线程才能继续访问资源。
如果有多个资源可以同时被多个进程或线程访问,那么信号量可以设置为大于1的值,表示可
用的资源数量。
每个进程或线程访问资源时,会将信号量减少相应数量。
当信号量的值为0时,表示所有资源都正在被使用,其他进程或线程需要等待。
当某个进程或线程释放资源时,会将
信号量增加相应数量,等待的进程或线程才能继续访问资源。
通过使用信号量,可以有效地控制对共享资源的并发访问,避免了竞态条件和死锁等问题,提
高了系统的可靠性和性能。
操作系统信号量与PV操作操作系统中的信号量是一种并发控制机制,用于对进程间共享的资源进行同步和互斥操作。
PV操作(也称为P操作和V操作)是信号量的两个基本操作,用于实现对信号量的减操作和增操作。
下面将详细介绍信号量和PV操作的概念、原理和应用。
一、信号量的概念:信号量是一种用于进程间通信和同步的工具,通过对信号量的操作来实现对共享资源的控制。
信号量的初值为非负整数,可以看作是一个计数器。
信号量的值表示可用资源的数量,当值大于0时表示有可用资源,当值为0时表示没有可用资源,当值小于0时表示有进程等待资源。
二、PV操作的原理:PV操作是对信号量进行加减操作,具体含义如下:1. P操作(wait操作):当进程需要使用一个资源时,首先执行P 操作。
P操作将信号量的值减1,如果值小于0,则进程被阻塞,等待资源的释放。
2. V操作(signal操作):当进程使用完一个资源后,需要释放资源,此时执行V操作。
V操作将信号量的值加1,如果值小于等于0,则唤醒等待资源的进程。
三、应用场景:信号量和PV操作在许多操作系统中被广泛应用,常见的应用场景如下:1.进程同步:信号量用于控制多个进程的执行顺序和互斥访问共享资源,确保进程间的顺序执行和资源的正确访问。
例如多个进程需要按照一定的顺序执行,可以使用信号量控制进程的执行顺序;多个进程需要互斥地访问一些共享资源,可以使用信号量进行同步。
2.互斥锁:信号量可以用于实现互斥锁,防止多个进程同时访问临界区。
通过将信号量初值设为1,并在进程需要访问临界区时执行P操作,实现对临界区的互斥访问。
3.生产者-消费者问题:信号量可以用于解决生产者-消费者问题,其中生产者和消费者共享一个有限大小的缓冲区。
通过定义两个信号量,一个表示空缓冲区的数量,一个表示满缓冲区的数量,可以实现生产者和消费者的同步和互斥访问。
4.读者-写者问题:信号量可以用于解决读者-写者问题,其中多个读者可以同时读取共享资源,但只有一个写者能够写入共享资源。
互斥量和信号量1. 什么是互斥量和信号量?1.1 互斥量(Mutex)互斥量是一种同步原语,用于控制对共享资源的访问。
它允许多个线程或进程并发执行,但是只有一个线程或进程可以同时访问共享资源。
当一个线程或进程要访问共享资源时,它必须先获得互斥量的所有权,其他线程或进程必须等待。
互斥量有两种状态:锁定和解锁。
当一个线程或进程获得互斥量的所有权时,它将互斥量锁定,并且其他线程或进程无法获得该互斥量的所有权。
只有当持有互斥量的线程或进程释放了该互斥量后,其他线程或进程才能获取到该互斥量的所有权。
1.2 信号量(Semaphore)信号量也是一种同步原语,用于控制对共享资源的访问。
与互斥量不同的是,信号量可以允许多个线程或进程同时访问共享资源。
信号量有一个计数器和一个等待队列。
当一个线程或进程要访问共享资源时,它必须先尝试获取信号量的所有权。
如果信号量的计数器大于零,线程或进程将获得信号量的所有权并继续执行。
如果信号量的计数器等于零,线程或进程将被阻塞并加入到等待队列中。
当持有信号量的线程或进程释放了该信号量后,等待队列中的一个线程或进程将被唤醒,并获得信号量的所有权。
这样就实现了多个线程或进程同时访问共享资源的控制。
2. 互斥量和信号量的应用场景2.1 互斥量的应用场景互斥量常用于以下情况:•多个线程需要访问共享资源,但是只能有一个线程能够访问。
•防止竞态条件(Race Condition)发生,保证共享资源在同一时间只被一个线程访问。
•在多线程编程中实现临界区(Critical Section)。
2.2 信号量的应用场景信号量常用于以下情况:•控制对有限资源(如数据库连接、文件句柄等)的并发访问。
•控制对共享数据结构(如缓冲区、队列等)的并发操作。
•控制对临界区(Critical Section)的并发访问。
3. 互斥量和信号量的实现方式3.1 互斥量的实现方式互斥量的实现方式有多种,常见的有以下几种:•基于硬件指令:一些处理器提供了硬件级别的原子操作指令,可以用来实现互斥量。
操作系统(三)——信号量、死锁1、信号量信号量机制:概念:其实就是⼀个变量,可以⽤⼀个信号量来表⽰系统中某种资源的数量、⽤户进程通过使⽤操作系统提供的⼀对原语来对信号量进⾏操作,从⽽⽅便的实现了进程互斥。
这⾥的⼀对原语是指wait(S)和signal(S),也简写为P(S)和V(S),即申请和释放资源。
P、V操作必须成对出现。
整数型信号量:⽤⼀个整数作为信号量,数值表⽰某种资源数。
对信号量的操作只有三种:初始化、P操作、V操作。
不满⾜让权等待原则。
记录型信号量:S.value表⽰某种资源数,S.L指向等待该资源的队列。
P操作中,先S.value++,之后可能执⾏block阻塞原语。
V操作中,先S.value--,之后可能执⾏wakeup唤醒原语。
可以⽤记录型信号量实现系统资源的申请和释放,申请S.value--,然后如果S.value<0说明资源分配完了,就阻塞;释放S.value++,然后如果S.value<=0说明还有进程在等待队列中等待,就唤醒。
记录型信号量可以实现进程互斥、进程同步。
实现进程互斥:划定临界区。
设置互斥信号量mytex,初值为1。
在临界区之前执⾏P(mutex),在临界区之后执⾏V(mutex)。
实现进程同步:分析那些地⽅是必须保证⼀前⼀后执⾏的两个操作。
设置同步信号量S,初始值为0。
在“前操作”之后执⾏V(S)。
在“后操作”之前执⾏P(S)。
实现前驱关系:每⼀对前驱关系都是⼀个进程同步问题。
为每⼀对前驱关系设置⼀个同步变量,初始值为0。
在“前操作”之后执⾏V操作。
在“后操作”之前执⾏P操作。
⽣产者消费者问题:⽣产者每次⽣产⼀个产品放⼊缓冲区,消费者每次从缓冲区取出⼀个产品使⽤。
缓冲区满⽣产者必须等待(同步关系1),缓冲区空消费者必须等待(同步关系2)。
缓冲区是临界资源,必须被互斥访问(互斥关系)。
问题中的P、V操作:⽣产者每次P⼀个缓冲区,V⼀个产品。
消费者每次V⼀个缓冲区,P⼀个产品。
c语言信号量的使用信号量是操作系统中用于实现进程间同步和互斥的一种机制。
在C 语言中,通过使用信号量,可以控制多个进程或线程的并发访问共享资源,避免出现竞态条件和死锁等问题。
信号量的使用通常涉及到三个主要操作:创建、等待和释放。
在C 语言中,可以使用系统提供的信号量函数来完成这些操作。
我们需要创建信号量。
在C语言中,可以使用semget函数来创建一个信号量集合。
该函数接受三个参数,分别是信号量的标识符、信号量的数量和信号量的访问权限。
创建成功后,semget函数会返回一个唯一的标识符,用于后续的操作。
接下来,我们可以使用semop函数来等待和释放信号量。
semop 函数接受三个参数,分别是信号量的标识符、一个指向sembuf结构体数组的指针和结构体数组的长度。
sembuf结构体中包含了信号量操作的相关信息,例如等待或释放信号量的数量。
对于等待操作,可以将sembuf结构体的sem_op字段设置为负数,表示等待信号量。
如果当前信号量的值大于等于等待的数量,则可以继续执行后续代码。
否则,当前进程或线程将被阻塞,直到信号量的值大于等于等待的数量。
对于释放操作,可以将sembuf结构体的sem_op字段设置为正数,表示释放信号量。
释放操作会增加信号量的值,从而允许其他进程或线程继续执行等待操作。
除了等待和释放操作外,还可以使用semctl函数来获取或修改信号量的值。
semctl函数接受三个参数,分别是信号量的标识符、要执行的操作和一个union semun结构体。
通过设置semun结构体的val字段,可以修改信号量的值。
在使用信号量时,需要注意以下几点。
首先,要确保所有的进程或线程都使用相同的信号量标识符,以便它们可以访问同一个信号量集合。
其次,要避免出现死锁的情况,即所有的进程或线程都在等待信号量,而没有释放信号量的操作。
为此,可以使用PV操作来保证互斥访问共享资源。
PV操作是指通过等待和释放信号量来实现进程间互斥的一种方法。
信号量和条件变量的异同点信号量和条件变量是操作系统中常用的同步机制,它们都可以用于线程之间的通信和协调,但在实际应用中有着不同的作用和特点。
我们来看看信号量。
信号量是一种用于控制对共享资源的访问的同步原语。
它通常用于限制同时访问某一资源的线程数量,或者用于实现生产者-消费者模式等场景。
信号量有两种类型:二进制信号量和计数信号量。
二进制信号量的取值只能为0或1,用于实现互斥访问共享资源;而计数信号量的取值可以大于1,用于控制对资源的访问数量。
与信号量类似,条件变量也是一种线程间同步的机制。
条件变量通常与互斥锁一起使用,用于在线程间传递信号和实现线程的等待和唤醒操作。
条件变量通过wait和signal操作来实现线程的等待和唤醒。
当一个线程调用wait操作时,它会释放互斥锁并进入等待状态,直到另一个线程调用signal操作唤醒它。
信号量和条件变量在功能上有一定的相似之处,都可以用于线程的同步和互斥控制。
但它们之间也存在一些明显的区别。
信号量是一种更为通用的同步原语,可以用于实现不同的同步策略,如互斥访问、资源控制等;而条件变量主要用于线程间的等待和唤醒操作,通常与互斥锁一起使用。
信号量是一个整数值,可以通过P和V操作进行增减;而条件变量是一个线程间共享的标识,用于线程的等待和唤醒。
信号量是一种无记忆的同步原语,它只关注当前资源的数量和可用性;而条件变量是一种有记忆的同步原语,可以用于线程间传递信号和信息。
在使用上,信号量通常用于控制对共享资源的访问,通过增减操作来实现资源的互斥访问;而条件变量通常用于线程的等待和唤醒操作,通过wait和signal操作来实现线程的同步和协调。
信号量和条件变量在操作系统中都扮演着重要的角色,它们都可以用于线程的同步和互斥控制。
虽然它们在功能上有一定的相似之处,但在实际应用中有着不同的作用和特点。
正确地选择和使用信号量和条件变量,可以有效地提高程序的性能和可靠性,实现线程间的协调和通信。
ucos信号量用法一、引言在嵌入式系统的开发中,ucos作为一个开源的实时操作系统,被广泛应用于各种嵌入式设备中。
信号量是ucos中一种重要的同步机制,用于解决多任务环境下资源竞争的问题。
本文将介绍ucos中信号量的用法和注意事项。
二、信号量的概念信号量是一种用于多任务同步和资源管理的机制。
在ucos中,信号量是一种计数型变量,用于实现任务的互斥访问和同步操作。
信号量可以有两个操作:等待(wait)和释放(signal)。
三、信号量的创建和初始化在ucos中,信号量的创建和初始化是通过调用相应的API函数实现的。
首先需要定义一个信号量的变量,然后通过调用API函数对其进行初始化。
例如,可以使用以下代码创建一个信号量并初始化为1:SEM_HANDLE sem;sem = OSSemCreate(1);在上述代码中,SEM_HANDLE是信号量的句柄类型,OSSemCreate()是ucos提供的一个用于创建和初始化信号量的函数。
四、信号量的等待操作信号量的等待操作是任务在使用共享资源之前进行的操作。
如果资源已被占用,则任务需要等待,直到资源可用。
在ucos中,可以通过调用OSSemPend()函数来完成等待操作。
以下是一个示例代码,展示了任务如何进行信号量等待操作:void Task1(void *arg){while(1){// 等待信号量OSSemPend(sem, 0, &err);// 使用共享资源// 释放信号量OSSemPost(sem);}}在上述代码中,任务会在OSSemPend()函数处等待信号量。
参数sem表示待等待的信号量句柄,0表示最大等待时间,&err用于记录等待的结果。
五、信号量的释放操作信号量的释放操作是任务在使用完共享资源后进行的操作。
通过调用OSSemPost()函数来释放信号量,使其他任务可以继续访问该资源。
以下是一个示例代码,展示了任务如何进行信号量释放操作:void Task2(void *arg){while(1){// 使用共享资源// 释放信号量OSSemPost(sem);}}在上述代码中,任务会在OSSemPost()函数处释放信号量,以便其他任务可以继续访问该资源。
信号量底层原理
信号量是一种线程同步工具,用于控制多个线程间的并发访问。
信号量底层原理一般基于原子操作和操作系统的原语实现。
常见的实现方式有基于计数器的二进制信号量和计数信号量。
1. 二进制信号量:
二进制信号量只有两个状态,通常用0表示锁定状态,用1表示解锁状态。
其底层原理一般基于原子操作实现,在多线程访问时,先检查信号量的状态,如果为锁定状态则等待,直到状态被解锁,则将状态设置为锁定状态,并进行相应的操作。
2. 计数信号量:
计数信号量的状态是一个整数,通常表示资源的可用数量。
其底层原理也基于原子操作,它包括两个主要操作:P操作和V
操作。
- P操作(也称为wait操作):当一个线程想要访问一个资源时,首先检查计数信号量的状态,如果计数大于0,则将计数
减1,并继续执行该线程的任务,否则线程被阻塞直到计数大
于0。
- V操作(也称为signal操作):当一个线程使用完一个资源后,它会通过V操作来释放资源,将计数信号量的计数加1,表示该资源可用。
在操作系统中,信号量的实现通常依赖于硬件的原子操作或者操作系统提供的原语,例如使用特定的机器指令或系统调用来
保证原子性。
不同的操作系统和编程语言可能提供不同的信号量实现方式,但底层的原理类似。
信号量的作用与使用方法一、引言信号量是一种用于同步和协调多个进程或线程的工具,它在多任务环境下起着至关重要的作用。
通过使用信号量,我们可以控制对共享资源的访问,避免竞争条件和死锁等问题,提高系统的效率和稳定性。
本篇文章将详细介绍信号量的作用与使用方法。
二、信号量的基本概念信号量是一个整数值,用于表示系统中可供使用的资源数量。
它通常用两个值来表示:非零值表示可用资源数量大于零,而零或负值表示资源数量不足。
通常用一个P(Proberen)和V(Verwerken)操作来改变信号量的值,P操作用于减少信号量的值,表示请求资源,如果资源可用,则减少资源数量并返回成功;如果资源不可用,则等待资源可用后再执行后续操作。
V操作用于增加信号量的值,表示释放资源,当一个进程完成了对资源的占用后,它可以通过执行V操作来释放资源供其他进程使用。
三、信号量的作用1. 同步:通过使用信号量,可以控制多个进程或线程对共享资源的访问。
当一个进程需要访问共享资源时,它会等待信号量变为可用状态,然后进入临界区访问资源。
这样,多个进程或线程可以按照一定的顺序访问共享资源,避免竞争条件和死锁等问题。
2. 避免资源浪费:通过使用信号量,可以控制资源的分配和释放,避免不必要的资源浪费和系统负载过高。
3. 协调任务执行:信号量可以用来协调多个任务之间的执行顺序和时间分配,从而提高系统的整体效率。
四、信号量的使用方法1. 初始化信号量:在使用信号量之前,需要先对其进行初始化。
通常,我们会使用一个初始值为1的信号量来表示共享资源的可用数量。
2. 申请资源:当一个进程需要访问共享资源时,它会使用P操作来请求资源。
如果资源可用,则减少资源数量并允许进程进入临界区;如果资源不可用,则该进程会被阻塞,直到信号量变为可用状态后再继续执行。
3. 释放资源:当一个进程完成对共享资源的访问后,它会使用V操作来释放资源。
这会增加信号量的值,以便其他进程可以申请资源。
信号量移植讲完了前面关于多线程的基础知识后,说一下我最近关于移植的一些体会.将win32程序关于多线程的内容移植到Linux下面,不能简单的按照函数对应来移植.不过通过下面的对应关系,再加上你对这些模式的深入了解,相信会移植的很成功.信号量Windows 信号量是一些计数器变量,允许有限个线程/进程访问共享资源.Linux POSIX 信号量也是一些计数器变量,可以用来在 Linux 上实现 Windows 上的信号量功能.∙信号量的类型: Windows 提供了有名(named)信号量和无名(unnamed)信号量.有名信号量可以在进程之间进行同步.∙在 Linux 上,在相同进程的不同线程之间,则只使用POSIX 信号量.在进程之间,可以使用 System V 信号量.∙等待函数中的超时:当在一个等待函数中使用时,可以为 Windows 信号量对象指定超时值.在 Linux 中,并没有提供这种功能,只能通过应用程序逻辑处理超时的问题.创建信号量在 Windows 中,可以使用CreateSemaphore()创建或打开一个有名或无名的信号量.HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCTSTR lpName);在这段代码中:∙lpSemaphoreAttributes是一个指向安全性属性的指针.如果这个指针为空,那么这个信号量就不能被继承.∙lInitialCount是该信号量的初始值.∙lMaximumCount是该信号量的最大值,该值大于 0.∙lpName是信号量的名称.如果该值为 NULL,那么这个信号量就只能在相同进程的不同线程之间共享.否则,就可以在不同的进程之间进行共享.这个函数创建信号量,并返回这个信号量的句柄.它还将初始值设置为调用中指定的值.这样就可以允许有限个线程来访问某个共享资源.在 Linux 中,可以使用sem_init()来创建一个无名的 POSIX 信号量,这个调用可以在相同进程的线程之间使用.它还会对信号量计数器进行初始化:int sem_init(sem_t *sem, int pshared, unsigned int value).在这段代码中:∙value(信号量计数器)是这个信号量的初始值.∙pshared可以忽略,因为在目前的实现中,POSIX 信号量还不能在进程之间进行共享.这里要注意的是,最大值基于 demaphore.h 头文件中定义的 SEM_VALUE_MAX. 在 Linux 中,semget()用于创建 System V 信号量,它可以在不同进程之间使用.可以用它来实现与 Windows 中有名信号量相同的功能.这个函数返回一个信号量集标识符,它与一个参数的键值关联在一起.当创建一个新信号量集时,对于与semid_ds数据结构关联在一起的信号量,semget()要负责将它们进行初始化,方法如下:∙sem_perm.cuid和sem_perm.uid被设置为调用进程的有效用户ID.∙sem_perm.cgid和sem_perm.gid被设置为调用进程的有效组 ID.∙sem_perm.mode的低 9 位被设置为semflg的低 9 位.∙sem_nsems被设置为nsems的值.∙sem_otime被设置为 0.∙sem_ctime被设置为当前时间.用来创建 System V 信号量使用的代码是:int semget(key_t key, int nsems, int semflg).下面是对这段代码的一些解释:∙key是一个惟一的标识符,不同的进程使用它来标识这个信号量集.我们可以使用ftok()生成一个惟一的键值.IPC_PRIVATE是一个特殊的key_t 值;当使用IPC_PRIVATE作为key时,这个系统调用就会只使用semflg 的低 9 位,但却忽略其他内容,从而新创建一个信号量集(在成功时).∙nsems是这个信号量集中信号量的数量.∙semflg是这个新信号量集的权限.要新创建一个信号量集,您可以将使用IPC_CREAT来设置位操作或访问权限.如果具有该 key 值的信号量集已经存在,那么IPC_CREAT/IPC_EXCL标记就会失败.注意,在 System V 信号量中,key被用来惟一标识信号量;在 Windows 中,信号量是使用一个名称来标识的.为了对信号量集数据结构进行初始化,可以使用IPC_SET命令来调用semctl()系统调用.将 arg.buf 所指向的 semid_ds 数据结构的某些成员的值写入信号量集数据结构中,同时更新这个结构的 sem_ctime member 的值.用户提供的这个 arg.buf 所指向的 semid_ds 结构如下所示:∙sem_perm.uid∙sem_perm.gid∙sem_perm.mode(只有最低 9 位有效)调用进程的有效用户 ID 应该是超级用户,或者至少应该与这个信号量集的创建者或所有者匹配:int semctl(int semid, int semnum, int cmd = IPC_SET, ...).在这段代码中:∙semid是信号量集的标识符.∙semnum是信号量子集偏移量(从 0 到nsems-1,其中 n 是这个信号量集中子集的个数).这个命令会被忽略.∙cmd是命令;它使用IPC_SET来设置信号量的值.∙args是这个信号量集数据结构中要通过IPC_SET来更新的值(在这个例子中会有解释).最大计数器的值是根据在头文件中定义的SEMVMX来决定的.打开信号量在 Windows 中,我们使用OpenSemaphore()来打开某个指定信号量.只有在两个进程之间共享信号量时,才需要使用信号量.在成功打开信号量之后,这个函数就会返回这个信号量的句柄,这样就可以在后续的调用中使用它了. HANDLE OpenSemaphore(DWORD dwDesiredAccess,BOOL bInheritHandle,LPCTSTR lpName)在这段代码中:∙dwDesiredAccess是针对该信号量对象所请求的访问权.∙bInheritHandle是用来控制这个信号量句柄是否可继承的标记.如果该值为 TRUE,那么这个句柄可以被继承.∙lpName是这个信号量的名称.在 Linux 中,可以调用相同的semget()来打开某个信号量,不过此时semflg的值为 0:int semget(key,nsems,0).在这段代码中:∙key应该指向想要打开的信号量集的 key 值.∙为了打开一个已经存在的信号量,可以将nsems和标记设置为0.semflg值是在返回信号量集标识符之前对访问权限进行验证时设置的.获取信号量在 Windows 中,等待函数提供了获取同步对象的机制.可以使用的等待函数有多种类型;在这一节中,我们只考虑WaitForSingleObject()(其他类型将会分别进行讨论).这个函数使用一个信号量对象的句柄作为参数,并会一直等待下去,直到其状态变为有信号状态或超时为止.DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );在这段代码中:∙hHandle是指向互斥句柄的指针.∙dwMilliseconds是超时时间,以毫秒为单位.如果该值是INFINITE,那么它阻塞调用线程/进程的时间就是不确定的.在 Linux 中,sem_wait()用来获取对信号量的访问.这个函数会挂起调用线程,直到这个信号量有一个非空计数为止.然后,它可以原子地减少这个信号量计数器的值:int sem_wait(sem_t * sem).在 POSIX 信号量中并没有超时操作.这可以通过在一个循环中执行一个非阻塞的sem_trywait()实现,该函数会对超时值进行计算:intsem_trywait(sem_t * sem).在使用 System V 信号量时,如果通过使用IPC_SET命令的semctl()调用设置初始的值,那么必须要使用semop()来获取信号量.semop()执行操作集中指定的操作,并阻塞调用线程/进程,直到信号量值为 0 或更大为止:int semop(int semid, struct sembuf *sops, unsigned nsops).函数semop()原子地执行在sops中所包含的操作——也就是说,只有在这些操作可以同时成功执行时,这些操作才会被同时执行.sops所指向的数组中的每个nsops元素都使用struct sembuf指定了一个要对信号量执行的操作,这个结构包括以下成员:∙unsigned short sem_num;(信号量个数)∙short sem_op;(信号量操作)∙short sem_flg;(操作标记)要获取信号量,可以通过将sem_op设置为 -1 来调用semop();在使用完信号量之后,可以通过将sem_op设置为 1 来调用semop()释放信号量.通过将sem_op设置为 -1 来调用semop(),信号量计数器将会减小 1,如果该值小于 0(信号量的值是不能小于 0 的),那么这个信号量就不能再减小,而是会让调用线程/进程阻塞,直到其状态变为有信号状态为止.sem_flg中可以识别的标记是IPC_NOWAIT和SEM_UNDO.如果某一个操作被设置了SEM_UNDO标记,那么在进程结束时,该操作将被取消.如果sem_op 被设置为 0,那么semop()就会等待semval变成 0.这是一个“等待为0” 的操作,可以用它来获取信号量.记住,超时操作在 System V 信号量中并不适用.这可以在一个循环中使用非阻塞的semop()(通过将sem_flg设置为IPC_NOWAIT)实现,这会计算超时的值.释放信号量在 Windows 中,ReleaseSemaphore()用来释放信号量.BOOL ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount);在这段代码中:∙hSemaphore是一个指向信号量句柄的指针.∙lReleaseCount是信号量计数器,可以通过指定的数量来增加计数.∙lpPreviousCount是指向上一个信号量计数器返回时的变量的指针.如果并没有请求上一个信号量计数器的值,那么这个参数可以是 NULL.这个函数会将信号量计数器的值增加在lReleaseCount中指定的值上,然后将这个信号量的状态设置为有信号状态.在 Linux 中,我们使用sem_post()来释放信号量.这会唤醒对这个信号量进行阻塞的所有线程.信号量的计数器同时被增加 1.要为这个信号量的计数器添加指定的值(就像是 Windows 上一样),可以使用一个互斥变量多次调用以下函数:int sem_post(sem_t * sem).对于 System V 信号量来说,只能使用semop()来释放信号量:int semop(int semid, struct sembuf *sops, unsigned nsops). 函数semop()原子地执行sops中包含的一组操作(只在所有操作都可以同时成功执行时,才会将所有的操作同时一次执行完).sops所指向的数组中的每个nsops元素都使用一个struct sembuf结构指定了一个要对这个信号量执行的操作,该结构包含以下元素:∙unsigned short sem_num;(信号量个数)∙short sem_op;(信号量操作)∙short sem_flg;(操作标记)要释放信号量,可以通过将sem_op设置为 1 来调用semop().通过将semop()设置为 1 来调用semop(),这个信号量的计数器会增加 1,同时用信号通知这个信号量.关闭/销毁信号量在 Windows 中,我们使用CloseHandle()来关闭或销毁信号量对象.BOOL CloseHandle(HANDLE hObject);hObject是指向这个同步对象句柄的指针.在 Linux 中,sem_destroy()负责销毁信号量对象,并释放它所持有的资源:int sem_destroy(sem_t *sem).对于 System V 信号量来说,只能使用semctl()函数的IPC_RMID命令来关闭信号量集:int semctl(int semid, int semnum, int cmd = IPC_RMID, ...)这个命令将立即删除信号量集及其数据结构,并唤醒所有正在等待的进程(如果发生错误,则返回,并将errno设置为EIDRM).调用进程的有效用户 ID是超级用户,或者可以与该信号量集的创建者或所有者匹配的用户.参数semnum会被忽略.。