什么是信号量
信号量与其他IPC对象不同,它是一个计数器,用于多个进程对共享数据对象的访问,它的本质是一种数据操作锁,它不像消息队列和管道那样具有数据交换的功能,而是通过控制其他的通信资源(文件,外部设备)来实现进程间通信。
如何通过信号量来控制进程间通信
为了获得共享资源,进程需要执行下列操作:
(1)、测试控制该资源的信号量;
(2)、若此信号量为正,则进程可以使用该资源,在这种情况下进程会将信号量值减一,表示它使用了一个资源单位;
(3)、若此信号量的值为0,则进程进入休眠状态,直至信号量值大于0,进程才被唤醒,此时又返回到步骤(1)。
注:信号量的测试和减一操作应当是原子操作,为此信号量通常是在内核中实现的。
为什么要使用信号量
使用信号量是为了防止因多个程序同时访问一个共享资源而引发的一系列问题,而信号量就是这样的一种方法,它可以保证任一时刻只能有一个执行线程访问代码的临界区域(临界区域是执行数据更新的代码需要独占式的执行),也就是说信号量是用来协调进程对共享资源的访问的。
操作系统是如何对信号量进行管理的
首先,内核为每个信号量集合维护着一个semid_ds结构
这个结构中包含了每个IPC对象都会包含的成员那就是ipc_perm(这个结构主要规定了IPC对象的权限和所有者),另外还含有信号量集合中元素数量sem_nsems成员,以及信号量处理的相关时间。
每个信号量其实是由一个无名结构体所表示的,它包含下列成员
struct {
unsigned short semval;
pid_t sempid;
unsigned short semncnt;
unsigned short semzcnt;
}
另外,操作系统还提供了相关的信号量系统调用接口,来使用户对信号量进行管理。
信号量接口函数
- 信号量的创建与获得
int semset(key_t key,int nsems,int flag);
//若成功,返回信号量ID,若失败,返回-1
当创建一个新的信号量集合时,要对semid_ds结构下列成员赋初值
sem_otime设置为0; //sem_otime是最后一次semop()的时间 sem_ctime设置为当前时间; //是最后一次调用semctl()的时间
sem_nsems设置为nsems; //信号量集合中的信号量数,如果是创建则必须要指定nsems,如果引用现有的那么将nsems设置为0即可。
- semctl包含了多种信号量操作
int semctl(int semid ,int semnum, int cmd,.../*union semun arg*/ );
该函数包含了对信号量的多种操作其中第四个参数是可选的,是否使用取决于cmd
如果使用了第四个参数,那么它的类型是 union semun;