各位看官们,大家好,上一回中咱们说的是使用信号量进行进程间同步与互斥的例子,这一回咱们继续说该例子。闲话休提,言归正转。让我们一起talk C栗子吧!
我们在上一回中介绍了如何使用信号量进行进程间同步与互斥,不过介绍的都是理论,这一回我们要通过具体的实践来介绍如何使用信号量进行进程间同步与互斥。光说不练,不是我们的作风,哈哈。
我们使用的Linux系统提供了信号量机制,并且提供了相应的API来操作信号量。信号量类似我们在前面章回中介绍的共享内存和消息队列,它也是System V IPC中的一部分,操作信号量的方法和操作共享内存以及消息队列的方法十分类似,接下来我们介绍与信号量相关的函数。
semget函数
int semget(key_t key,int num_sems, int sem_flag)
该函数用来创建一个新的信号量或者获取已经存在的信号量。
- 第一个参数是键值,通过它来操作IPC在内核中的结构,也就是信号量在内核中的结构;(前面章回中介绍过)
- 第二个参数是信号量的数目,通常为1;
- 第三个参数表示操作信号量的权限,该权限和文件权限一样;
- 该函数运行成功时返回信号量的标识符,否则返回-1;我们可以通过该标识符使用信号量;
semop函数
int semop(int sem_id, struct sembuf *sem_ops,size_t sem_ops_num)
该函数用来修改信号量的值,也就是对信号量的P/V操作;
- 第一个参数是信号量的标识符,通过semget函数可以获得;
- 第二个参数是一个指针,该指针指向结构体类型的变量,该变量中包含中对信号的操作内容和操作方式;
- 第三个参数表示信号量操作的数量,也就是第二个参数的数量,通常为1;
- 该函数运行成功时返回0,否则返回-1;
函数的第二个参数的类型是一个结构体,该结构体的定义如下:
struct sembuf
{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
}
我们详细介绍一下该结构体的成员:
- 第一个成员表示信号量的编号,通常为0,表示单个信号量,如果非0,则表示一组信号量;
- 第二个成员表示对信号量操作的数值,通常为1或者-1,也就是对信号量加1或者减1(对应V/P操作);
- 第三个成员表示对信号量的操作方式,通常为SEM_UNDO,表示让系统对信号量进行跟踪处理;
该函数代表的动作是一个原子操作,使用它的时候,不用担心是否会被其它操作中断。
semctl函数
int semctl(int sem_id, int sem_num, int cmd, ...)
该函数用来控制信号量,通常用来初始化或者删除信号量;
- 第一个参数是信号量的标识符,通过semget函数可以获得;
- 第二个参数是信号量的编号,通常为0,表示单个信号量,如果非0,则表示一组信号量;
- 第三个参数是一个命令,该命令有许多个,常用的是SETVAL和IPC_RMID,表示初始化和删除信号量;
- 该函数是可变参数的函数,可能还有其它类型的参数;
- 该函数运行成功时返回0,否则返回-1;
我们在使用该函数的时候通常都需要第四个参数,该参数为一个联合体类型,详细的定义如下所示:
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
如果系统中没有定义该类型的话,我们需要定义该类型。
- 如果第三个参数赋值为SETVAL时,表示初始化信号量,我们需要第四个参数,并且使用semun中val值去初始化信号量。
- 如果第三个参数赋值为IPC_RMID,表示删除信号量,那么不需要第四个参数。
各位看官,关于使使用信号量进行进程间同步与互斥的例子咱们就说到这里。欲知后面还有什么例子,且听下回分解 。