一、进程间通讯——信号量
信号量:信号量实现的是一种类似于计数器的功能,用于为多个进程提供对共享数据对象的访问。主要是用于实现进程间的互斥和同步。
临界资源:同一时刻仅能被一个进程访问的资源。
原子操作:不能被中断的操作。
为了获取共享资源,进程需要执行下列操作:
(1)测试控制该资源的信号量
(2)若此信号量为正,则表示进程可以使用该资源。在这种情况下,进程会将信号量值减1,表示使用了一个资源单位;
(3)否则,若此信号量值为0,则进程进入休眠状态,直至信号量值大于0,。进程被唤醒后,它会返回至步(1);
当进程不再使用由一个信号量控制的共享资源时,该信号量值加1,。如果有进程正在休眠等待此信号量,则唤醒它们;
二、信号量的控制结构
为了正确地实现信号量,信号量值的测试及减1应当是原子操作。为此信号量有一个在内核实现的控制结构。这个控制结构在创建信号量成功后,由内核产生。其结构声明位于头文件bits/sem.h中
内核为每个信号量集合维护着一个semid_ds 结构:
struct semid_ds
{
struct ipc_perm sem_perm; //许可权限结构
unsigned short sem_nsems;//信号量集中的信号量个数,linux系统可以对一个信号量集进行操作好和控制
time_t sem_otime;//最后一次semop操作的时间
time_t sem_ctime;//最后一次调用semctl 改变信号量的时间
···
···
···
};
每个信号量由一个无名结构表示,它只少包含下列成员:
struct {
unsigned short semval;//信号量的值(>=0)
pid_t sempid;//
unsigned short semncnt;
unsigned short semzcnt;
};
三、信号量的操作
1、创建: 首先需要通过调用函数semget来获取一个信号量ID
int semget( key_t key,int nsems, int flag);
//返回值:若成功,返回信号量ID;若出错,返回-1;
key_t key //键值,唯一标识一个信号量
int nsems //信号量集中信号量的个数
int flag //创建信号量标志。主要包含两方面的信息:一是访问权限信息,该权限信息将初始化信号量控制结构中的sem_perm权限结构;二、创建标志,主要的创建标志包括IPC_CREAT、IPC_EXCL等
在信号量创建成功以后,就可以通过信号量操作实现进程的互斥和同步。
2、P、V操作:
#include <sys/sem.h>
int semop(int semid, struct sembuf semoparray[ ] , size_t nops);
//返回值:若成功,返回0;若出错,返回-1;
参数说明:
int semid :输入参数,信号量集的标识符。该标识符是通过semget返回的
size_t nops :输入参数,操作的信号量个数。每次semop调用可以对一个信号量集中的多个信号量进行操作
struct sembuf semoparray[ ] :参数 semoparray是一个指针,它指向一个由sembuf结构表示的信号量操作数 组:该参数表明了对该信号量集操作的详细情况;
struct sembuf{
unsigned short sem_num; //信号集中信号量的编号(0~nsems-1)
short sem_op; //具体操作(+1或-1)
short sem_flg;//信号量的操作标志 IPC_NOWAIT,SEM_UNDO
}
3、信号量控制
在进行信号量操作时,经常需要对信号量进行控制,如设置信号量的值、获取信号量的值等。linux系统提供了semctl函数完成对信号量的控制。
int semtcl ( int semid, int semnum, int cmd,······)
参数说明:
int semid :输入参数,信号量集的标识符。该标识符是通过调用semget返回的
int semnum:输入参数,信号量的编号。信号量在信号量集中的索引
int cmd: 输入参数,信号量控制命令
······ :输入参数,控制命令参数。对于不同的控制命令,其参数格式是不同的。为了满足这一需求,该参数 使用了联合,其原型如下;
union semun{
int val;//用于SETVAL控制命令。整型变量,用于设置信号量的值
struct semid_ds *buf;//用于IPC_STAT和IPC_SET控制命令。指向semid_ds结构指针,用于 获取或者设置信号量控制结构。
unsigned short *array;//用于GETALL和SETALL控制命令。指向短整型数组的指针,用于获 取或者信号量集的值
};
四、管理系统上所有信号量的命令
1、查看系统所有的信号量集: ipcs -s
2、删除系统中的信号量集: ipcrm -s semid