(本节笔记的实验代码,在这里)
1. 信号量
1.1 基本概念:主要用于保护临界资源(进程互斥),进程可以根据此判定是否能够访问某些共享资源。除了用于访问控制以外,还可用于进程间的同步。
1.2 分类:第一种是二值信号,只能取0或1;第二种是计算信号量,可取任意非负值。
2. 函数学习
2.1 创建信号量集合
函数名:
semget
函数原型:
int semget (key_t key, int nsems, int semflg);
函数功能:
获取信号量的标识符,若key指定的信号量集合不存在,若semflg里包含了IPC_CREAT,则创建一个信号量集合。
所属头文件:
<sys/types.h> <sys/ipc.h> <sys/sem.h>
返回值:
成功:返回信号量集合的标识符 失败:返回-1
参数说明:
key:“键值”,一个数字,相当于文件的pathname,ipc对象都有一个键值
构造方法:key_t ftok (char *fname, int id);
fname文件名 ——>对应的数字——>
项目ID ——> 由对应数字和项目ID得出key
nsems:创建的信号量集合所包含的信号量数目
semflg:IPC_CREAT,若信号量集合不存在,则创建,信号量的数目由nsems指定
2.2 操作信号量集合
函数名:
semop
函数原型:
int semop (int semid, struct sembuf *sops, unsigned nsops);
函数功能:
操作信号量
所属头文件:
<sys/types.h> <sys/ipc.h> <sys/sem.h>
返回值:
成功:返回0 失败:返回-1
参数说明:
semid:要操作的信号量集合的标识符
sops:是一个struct的地址
struct sembuf{
unsigned short sem_num /* 需要操作的信号量的号码 */
short sem_op /* 对信号量的操作,正数为释放,负数为获取,获取失败会导致进程等待 */
short sem_flg /* 操作的标志 SEM_UNDO */
}
nsops:要操作多少个信号量
2.3 操作信号量
函数名:
semctl
函数原型:
int semctl (int semid, int semnum, int cmd, ...);
函数功能:
对信号量的操作,如查看或者设置信号量的值等。
所属头文件:
<sys/sem.h>
返回值:
根据各cmd的不同而有所不同
参数说明:
semid:要操作的信号量集合的标识符
semnum:要操作的信号量的号码
cmd:操作的方式,如:
SETVAL:设定semnum的semval值
GETVAL:获取semnum的semval值
参数4:要设定的值
3. 综合实例
/* 有这么的设定 */
/******************************************************************************
在一个文件中,进程A写入“aaaaa”,然后sleep(10),再写入“bbbbb”,
进程B对同一个文件写入“ccccc”,利用互斥信号量,是的B在A写完后再写
******************************************************************************/
/* touch a_student.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
int main(int argc, char ** argv)
{
int val_sem;int fd_sem;
int semnum_sem;
key_t key_sem;
struct sembuf buf_sem;
fd_sem = open("./sem.txt",O_RDWR | O_APPEND | O_CREAT, 0777);
printf("fd_sem val is %d\n",fd_sem);
key_sem = ftok("/arm/key_sem", 1);
printf("key_sem val is %d\n",key_sem);
semnum_sem = semget(key_sem, 1, IPC_CREAT);
printf("semnum_sem val is %d\n",semnum_sem);
val_sem = semctl(semnum_sem, 0, GETVAL);
printf("a val is %d\n", val_sem);
semctl(semnum_sem, 0, SETVAL, 1);
val_sem = semctl(semnum_sem, 0, GETVAL);
printf("a val is %d\n", val_sem);
buf_sem.sem_num = 0;
buf_sem.sem_op = -1;
semop(semnum_sem, &buf_sem, 1);
write(fd_sem,"aaaaa",5);
sleep(10);
write(fd_sem,"bbbbb",5);
buf_sem.sem_num = 0;
buf_sem.sem_op = 1;
semop(semnum_sem, &buf_sem, 1);
close(fd_sem);
return 0;
}
/* touch b_student.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
int main()
{
int val_sem;
int fd_sem;
int semnum_sem;
key_t key_sem;
struct sembuf buf_sem;
fd_sem = open("./sem.txt",O_RDWR | O_APPEND | O_CREAT, 0777);
printf("fd_sem val is %d\n",fd_sem);
key_sem = ftok("/arm/key_sem", 1);
printf("key_sem val is %d\n",key_sem);
semnum_sem = semget(key_sem, 1, IPC_CREAT);
printf("semnum_sem val is %d\n",semnum_sem);
val_sem = semctl(semnum_sem, 0, GETVAL);
printf("B val is %d\n", val_sem);
buf_sem.sem_num = 0;
buf_sem.sem_op = -1;
semop(semnum_sem, &buf_sem, 1);
write(fd_sem,"ccccc",5);
buf_sem.sem_num = 0;
buf_sem.sem_op = 1;
semop(semnum_sem, &buf_sem, 1);
close(fd_sem);
return 0;
}