临界资源:同一时刻只允许一个进程访问资源
临界区:访问临界资源的代码段。
获取资源则-1, p操作,会阻塞
释放资源则+1,v操作,不会阻塞
p,v操作皆为原子操作,不会被打断
ipcs -s查看信号量
ipcrm -s +地址 删除信号量
打印
临界资源
0/1
A B
p() p() 阻塞
for(i=0;i<4;i++) for(i=0;i<6;i++)
printf(A) printf(B)
printf(A) printf(B)
v() v()
此过程称为同步。
信号量的封装
//创建文件sem.h存放函数声明
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<assert.h>
#include<sys/sem.h>
union semun
{
int val;
};
void sem_init();//创建或获取信号量
void sem_p();//P操作
void sem_v();//V操作
void sem_destroy();//销毁操作
//直接调用sem.h函数
#include"sem.h"
static int semid = -1;//全局变量,由于后面int返回值为地址,所以必须将初始值定为-1;static是只在当前文件中有效。
void sem_init()
//考虑是否已有信号量,若无则创建,若有则error获取已有信号量。
{
//create init 1
semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);//全新创建
if(semid == -1)//表示失败
{
semid = semget((key_t)1234,1,0600);
if(semid == -1)
{
perror("semget error");
return;
}
}
else//表示成功
{
union semun a;
a.val = 1;
if (semctl(semid,0,SETVAL,a)==-1)
{
perror("semctl error");
}
}
}
void sem_p()
{
struct sembuf buf;
buf.sem_num=0;
buf.sem_op=-1;
buf.sem_flg=SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
perror("semop error");
}
}
void sem_v()
{
struct sembuf buf;
buf.sem_num=0;
buf.sem_op=1;
buf.sem_flg=SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
perror("semop error");
}
}
void sem_destroy()
{
if(semctl(semid,0,IPC_RMID)==-1)
{
perro("semtcl error");
}
}
信号量的使用
//打印A
#include"sem.h"
int main()
{
sem_init();
int i=0;
for(;i<5;i++)
{
sem_p();//P操作-1
printf("A");
fflush(stdout);
int n=rand()%3;//随机值对三取余
sleep(n);
printf("A");
fflush(stdout);
sem_v();//V操作+1
n=rand()%3;
sleep(n);
}
}
//打印B
#include "sem.h"
int main()
{
sem_init();
int i=0;
for(;i<5:i++)
{
sem_p();//p操作
printf("B");
fflush(stdout);//刷新标准输入缓冲区
int n=rand()%3;
sleep(n);//睡眠随机时间
printf("B");
fflush(stdout);
sem_v();//v操作
n=rand()%3;
sleep(n);
}
sem_destroy();//销毁,只能销毁一次
exit();
}