一、信号量(semaphore)
在进程互斥中,信号量主要用来保护临界资源。进程通过信号量来判断
是否能够访问该共享资源。(当然,后面我们还会用来控制进程同步)。
二、信号量类型
1、二值信号量:信号量的取值为 0 或者 1
2、计数信号量:信号量的取值为任意非负数
三、键值 : 文件标示符 + 项目ID
1、任意指定一个数:若该数已被使用,则不能与信号量关联(失败)
2、构造一个数:使用ftok()构造
3、了解键值: 来自新浪博客 路在脚下 深入解读键值产生原理,linux中的软链接和硬链接
四、函数学习
1、创建 / 打开信号量集合:semget
1)函数原型
int semget(key_t key, int nsems, int semflg);
2)所属头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
3)返回值
成功: 返回信号量集合标识符(非负整数); 当信号量<0时访问该信号量的其他进程等待
失败: -1
4)参数说明
key: 信号量的键值
nsems: 信号量的数目
semflg: 同open()函数的权限位
2、操作信号量:semop
1)函数原型
int semop(int semid, struct sembuf *sops, unsigned nsops);
2)所属头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
3)返回值
成功: 0
失败: -1
4)参数说明
semid: 要操作的信号量集合的标识符
sops: 对信号量执行什么操作
nsops: 要操作的信号量数目
struct sembuf sops{
unsigned short sem_num; /* 信号量序号 */
short sem_op; /* 对信号量操作 */
short sem_flg; /* operation flags */
}
3、键值转换:ftok
1)函数原型
key_t ftok(const char *pathname, int proj_id);
2)所属头文件
#include <sys/types.h>
#include <sys/ipc.h>
3)返回值
成功: 返回生成的键值
失败: -1
4)参数说明
pathname: 包含路径的文件名
proj_id: 项目序号
4、信号量控制操作:semctl
1)函数原型
int semctl(int semid, int semnum, int cmd, ...);
2)所属头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
3)返回值
成功: 返回一个非负整数(取决于cmd)
失败: -1
4)参数说明
semid: 信号量集合
semnum: 集合中的信号量序号
cmd: 命令
* 最佳实践 - 1:
/* op_1.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#define FILE_NAME "./BOARD.TXT"
void main()
{
int fd = 0;
key_t key = 0;
int semid = 0;
int sem_val = 0;
struct sembuf sops;
/* 创建键值. */
key = ftok("/home/taylor/linux-3/signal-process/BOARD.TXT",1);
/* 创建并打开信号量集合. */
semid = semget(key, 1, IPC_CREAT);
/* 设置信号量初值为1.默认不为0 */
sem_val = semctl(semid, 0, SETVAL, 1);
printf("Semaphore init value is : %d\n", sem_val);
/* 打开信息文件. */
fd = open(FILE_NAME, O_RDWR | O_APPEND);
/* 获取信号量.*/
sops.sem_num = 0;
sops.sem_op = -1;
semop(semid, &sops, 1);
/* 插入数据. */
write(fd, "I Love ", 7);
sleep(10); //等待, 这里运行op_2, 检测是否互斥
write(fd, "You.", 4);
/* 释放信号量. */
sops.sem_num = 0;
sops.sem_op = 1;
semop(semid, &sops, 1);
/* 关闭文件. */
close(fd);
}
* 最佳实践 - 2:
/* op_2.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#define FILE_NAME "./BOARD.TXT"
void main()
{
int fd = 0;
key_t key = 0;
int semid = 0;
int sem_num = 0;
struct sembuf sops;
/* 创建键值. */
key = ftok("/home/taylor/linux-3/signal-process/BOARD.TXT",1);
/* 打开信号量集合. */
semid = semget(key, 1, IPC_CREAT);
/* 获取信号量初始化. */
sem_num = semctl(semid, 0, GETVAL);
printf("Student2 get init value is: %d\n", sem_num);
/* 打开信息文件. */
fd = open(FILE_NAME, O_RDWR | O_APPEND);
/* Get semaphore. */
sops.sem_num = 0;
sops.sem_op = -1; //当信号量<0时, 执行等待
semop(semid, &sops, 1);
/* 插入信息,看看是否插队op_1 */
write(fd, "pig is you ", 11);
/* Release semaphore. */
sops.sem_num = 0;
sops.sem_op = 1;
semop(semid, &sops, 1);
close(fd);
}
输出:
* 先后台运行op_1 # ./op_1 &
* 再运行op_2 # ./op_2
* 从结果可以看出, 若在sleep(10)等待时没有互斥现象, 则输出内容为: I Love pig is you You. 信息将错乱