信号量(又名:信号灯)与其他进程间通信方式不大相同,主要用途是保护临界资源(进程互斥)。进程可以根据它判定是否能够访问某些共享资源。除了用于访问控制外,还可用于进程同步。
信号量的分类:
-
二值信号灯:信号灯的值只能取0或1
-
计数信号灯:信号灯的值可以取任意非负值。
信号量的实质:1、数字 2、操作,包括释放和获取两种情况。
8.1 创建/ 打开信号量集合
8.1.1 函数名 semget
8.1.2 函数原形 int semget(key_t key, int nsems, int sem***);
8.1.3 函数功能 获取信号量集合的标识符
8.1.4 所属头文件 <sys/types.h> <sys/ipc.h> <sys/sem.h>
8.1.5 返回值 成功:返回信号量集合的标识符 失败:-1
8.1.6 参数说明
key:键值 sem***:标志,可以取IPC_CREAT nsems:创建的这个信号量集合里面包含的信号量的数目
8.1.7 范例代码
8.2 操作信号量
8.2.1 函数名 semop
8.2.2 函数原形 int semop(int semid, struct *sops, unsigned nsops, struct timespec *timeout);
8.2.3 函数功能 操作信号量集里面的信号量
8.2.4 所属头文件 <sys/types.h> <sys/ipc.h> <sys/sem.h>
8.2.5 返回值 成功:返回0 失败:返回-1
8.2.6 参数说明 semid:要操作的信号量集合的标识符 nsops:要操作多少个信号量 sops:堆信号量执行什么样的操作,实则sops包含了下面这个结构体:其中sem_num:指定了是信号量集合的第几个信号量。sem_op:若sem_op为n。n>0则表示释放了n个信号量。n<0则表示获取了n个信号量
8.3 信号量的控制
8.3.1 函数名 semctl
8.3.2 函数原形 int semctl(int semid, int semnum, int cmd, ...);
8.3.3 函数功能 控制信号量
8.3.4 所属头文件 <sys/types.h> <sys/ipc.h> <sys/sem.h>
8.3.5 返回值 成功:根据cmd返回不同的非负值 失败:-1
8.3.6 参数说明 semid:信号量集合的标识符 semnum:信号量集合的哪个信号量 cmd:相应的控制命令(GETVAL:返回成员semnum的semval值, SETVAL:设置成员semnum的semval值。该值由arg.val指定)。
8.4 获取key值
8.4.1 函数名 ftok
8.4.2 函数原形 key_t ftok(const char *pathname, int proj_id);
8.4.3 函数功能 将路径名和项目标识符转化为一个进程间信号量通信的key值
8.4.4 所属头文件 <sys/types.h> <sys/ipc.h>
8.4.5 返回值 成功:key值将被返回 失败:-1
8.4.6 参数说明 pathname:路径名 proj_id:自定义的数字id
小实验:假设有这样的场景:数学课代表A要在公示栏上写“math cancel”这样一个通知。当他写完“math”后,电话铃响了。然后出去接了个电话。正在这时英语课代表B也要写通知,通知内容是“English exam”。这时公示栏上的内容是“math English exam”。B写完后,A又不管三七二十一的写上了“cancel”。这时黑板上的内容为“math English exam cancel”。从而引起了歧义。代码如下:
astudent.c:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fd;
fd = open("/home/board.txt",O_RDWR|O_APPEND);//读取txt文件
write(fd, "math", 5);
sleep(3);
write(fd, " cancel", 7);
close(fd);
return 0;
}
bstudent.c:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fd;
fd = open("/home/board.txt",O_RDWR|O_APPEND);//读取txt文件
write(fd, "English exam", 13);
return 0;
}
公示栏上的内容为下图:
那么,怎样消除这样的问题呢?我们可以看出这两个事件是互斥的。我们可以通过设置一个信号量来解决。当A开始写通知的时候生成一个标志位。直至A写完通知,标志位状态改变,B开始写通知。
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int main()
{
int fd = 0;
int semid;
key_t key;
struct sembuf sops;
int ret;
key = ftok("/home", 1);
semid = semget(key, 1, IPC_CREAT);
semctl(semid, 0, SETVAL, 1);
fd = open("/home/board.txt",O_RDWR|O_APPEND);//读取txt文件
sops.sem_num = 0;
sops.sem_op = -1;
semop(semid, &sops, 1);
write(fd, "math", 5);
sleep(10);
write(fd, " cancel", 7);
sops.sem_num = 0;
sops.sem_op = 1;
semop(semid, &sops, 1);
close(fd);
return 0;
}
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int main()
{
int fd = 0;
int semid;
key_t key;
struct sembuf sops;
int ret;
key = ftok("/home", 1);
semid = semget(key, 1, IPC_CREAT);
fd = open("/home/board.txt",O_RDWR|O_APPEND);//读取txt文件
sops.sem_num = 0;
sops.sem_op = -1;
semop(semid, &sops, 1);
write(fd, "English exam", 13);
sops.sem_num = 0;
sops.sem_op = 1;
semop(semid, &sops, 1);
close(fd);
return 0;
}
文章评论(0条评论)
登录后参与讨论