临界资源:
多道程序系统中存在许多进程,他们共享各种资源,然而又很多资源一次只能供一个进程使用。一次仅允许一个进程使用的资源称为临界资源。许多物理设备属于临界资源,如打印机等。
信号量:
信号量与其他IPC不同,这是一个计数器,信号量用于实现进程之间的互斥与同步,而不是用于进程间的数据通信。
特点:
1.信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
2.信号量是基于操作系统的PV操作(P相当于取锁对信号量的值进行-1,V相当于放回锁,对信号量的值进行+1),程序对信号量的操作都是原子操作。(原子操作:原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束)
3.支持信号量集(操作多个信号量)。
//int semget(key_t key, int nsems, int semflg);
//int semctl(int semid, int semnum, int cmd, …);
//int semop(int semid, struct sembuf *sops, size_t nsops);
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include<unistd.h>
//int semget(key_t key, int nsems, int semflg);
//int semctl(int semid, int semnum, int cmd, ...);
//int semop(int semid, struct sembuf *sops, size_t nsops);
void pGetKey(int id) //P操作取锁函数
{
struct sembuf sops; //定义semop函数中的第二个结构体
sops.sem_num = 0; //信号量编号,默认为0
sops.sem_op = -1; //P操作对原来的seminit.val的值减1
sops.sem_flg = SEM_UNDO; //不能用IPC_NOWAIT
semop(id,&sops,1); //第三个参数为选取的信号量个数
printf("get key\n");
}
void vPutBackKey(int id) //V操作与P操作类似
{
struct sembuf sops;
sops.sem_num = 0;
sops.sem_op = 1; //V操作对seminit.val的值进行加1
sops.sem_flg = SEM_UNDO;
semop(id,&sops,1);
printf("put back key\n");
}
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) */
};
int main()
{
int semID;
pid_t pid;
key_t key;
key = ftok(".",2);
semID = semget(key,1,IPC_CREAT|0666); ///创建信号量,第二个参数是设置几个信号量
if(semID == -1){
printf("semget failure\n");
}
union semun seminit;
seminit.val = 0; //设置信号量的初值为0
semctl(semID,0,SETVAL,seminit); //初始化信号量, 第二个参数是对第几个信号量进行操作,第三个为操作指令,第四个操作指令对应操作为联合体
pid = fork();
if(pid > 0){
printf("this is father pid\n");
vPutBackKey(semID); //为了让父进程先运行,在对信号量初始化时设置信号量的值为0,此时相当于无锁状态
}else if(pid == 0){ //在父进程末尾调用V操作放回信号量,在子进程开始时就使用P操作取信号量
pGetKey(semID); //由于子进程无法取到信号量所以只能由父进程先运行等到父进程放回信号量后子进程才能取信号量
printf("this child pid\n");
vPutBackKey(semID);
}else{
printf("fork error\n");
}
return 0;
}