信号量,本质是一个计数器,这个计数器用来描述临界资源的数目;
原子性,要么读(写)完,要么不读(写);
信号量既是用来解决进城同步与互斥问题的机制,也可以实现进程间通信;
临界资源:不同进程能够看到的同一份资源;
临界区:双方访问临界资源的那份代码(read、write);
通过保护临界区来保护临界资源;
互斥:任何时刻只有一个进程原子性的访问临界资源;
饥饿:长时间未得到某种资源;
同步:大部分在互斥的前提下,以某种顺序依次访问临界资源;
p操作:-1(信号量sem的值减1,sem=sem-1),如果sem>0该进程继续执行,否则该进程置为等待状态,排入等待队列;
v操作:+1(信号量sem的值加1,sem=sem+1),如果sem>0该进程继续执行,否则释放队列中第一个等待信号量的进程。
信号量要被不同的进程看到,其本身就是临界资源,信号量的操作包括创建,初始化,获取,释放
信号量的两种状态:二元信号量(表示资源只有一个,本身可以提供互斥机制),多元信号量
comm.h
#ifndef _COMM_H_
#define _COMM_H_
#define PATHNAME "."
#define PROJ_ID 0666
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<unistd.h>
typedef 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 */
void *__pad;
}mysemun;
int create_sems(int nums);
int get_sems();
int destory_sems(int semid);
int init_sems(int semid,int which,int _val);
int P(int semid,int which);
int V(int semid,int which);
int comm_sems(int nums,int flags);
int comm_semop(int semid,int which,int op);
#endif
comm.c
#include"comm.h"
int comm_sems(int nums,int flags)
{
key_t key=ftok(PATHNAME,PROJ_ID);
int semid=semget(key,nums,flags);
if(semid<0)
{
perror("semget");
return -1;
}
return semid;
}
int create_sems(int nums)
{
return comm_sems(nums,IPC_CREAT | IPC_EXCL | 0666);
}
int get_sems()
{
return comm_sems(0,IPC_CREAT);
}
int init_sems(int semid,int which,int _val)
{
mysemun un;
un.val=_val;
if(semctl(semid,which,SETVAL,un)<0)
{
perror("semctl");
return -1;
}
return 0;
}
int destory_sems(int semid)
{
if(semctl(semid,0,IPC_RMID)<0)
{
perror("semctl");
return -1;
}
return 0;
}
int comm_semop(int semid,int which,int op)
{
struct sembuf sbuf;
sbuf.sem_num=0;
sbuf.sem_op=op;
sbuf.sem_flg=SEM_UNDO;
if(semop(semid,&sbuf,1)<0)
{
perror("semop");
return -1;
}
return 0;
}
int P(int semid,int which)
{
return comm_semop(semid,which,-1);
}
int V(int semid,int which)
{
return comm_semop(semid,which,1);
}
sems.c
#include"comm.h"
int main()
{
int semid=create_sems(1);
init_sems(semid,0,1);
pid_t pid=fork();
if(pid<0)
{
perror("fork");
return -1;
}
else if(pid==0)
{
//child
get_sems();
while(1)
{
P(semid,0);
printf("A");
usleep(12345);
fflush(stdout);
printf("A");
usleep(22345);
fflush(stdout);
V(semid,0);
}
}
else
{
//father
while(1)
{
P(semid,0);
printf("B");
fflush(stdout);
usleep(12345);
printf("B");
usleep(22345);
fflush(stdout);
V(semid,0);
}
waitpid(NULL);
destory_sems(semid);
}
return 0;
}
Makefile
sems:comm.c sems.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f sems
使用P、V操作之前
使用P、V操作之后