8.15 信号量
(1)概念
信号量是一个特殊的变量,一般取正数值。它的值代表允许访问的资源数目。
Р操作:获取资源时,需要对信号量的值进行原子减一
当信号量值为0时,代表没有资源可用,Р操作会阻塞。
V操作:释放资源时,需要对信号量的值进行原子加一
!信号量主要用来同步进程!
信号量的值如果只取0、1,将其称为二值信号量。如果信号量的值大于1,则称之为计数信号量。
临界资源:同一时刻 只允许被一个进程或线程访问的资源
临界区:访问临界资源的代码段
(2)信号量使用
操作信号量的接口介绍:
int semget(key_t key,int nsems,int semflg); //创建信号量
int semop(int semid,struct sembuf*sops,unsigned nsops); //P V操作
int semctl(int semid,int semnum,int cmd,...); //销毁信号量 cmd信号量初始化
(sem.h)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sem.h>
union semun
{
int val;
};
void sem_init();
int sem_p();
int sem_v();
void sem_destory();
(sem.c)
#include "sem.h"
static int semid = -1;
void sem_init()
{
semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600); //全新创建信号量
if(semid == -1) //全新创建失败 信号量可能已经存在
{
semid = semget((key_t)1234,1,IPC_CREAT|0600);
if(semid == -1)
{
printf("creat sem failed\n");
return;
}
}
else
{
union semun a;
a.val = 1; //信号量的初始值
if(semctl(semid,0,SETVAL,a) == -1) //初始化信号量
{
printf("sentl setval error\n");
return;
}
}
}
int sem_p()
{
struct sembuf buf;
buf.sem_sun = 0;
buf.sem_op = -1; //p
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1) == -1)
{
printf("semop p err\n");
return -1;
}
return 0;
}
int sem_v()
{
struct sembuf buf;
buf.sem_sun = 0;
buf.sem_op = 1; //v
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1) == -1)
{
printf("semop v err\n");
return -1;
}
return 0;
}
void sem_destory()
{
if(semctl(semid,0,IPC_RMID) = -1)
{
printf("semctl del err\n");
}
}
ipcs 查看消息队列 共享内存 信号量数目
ipcs -s 查看信号量
ipcrm -s 1(semid) 删除信号量
!!笔试例题
三个进程ABC运用信号量最终打印出"ABCABCABC…"
(sem.h)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sem.h>
#define SEM_MAX 3
#define SEM1 0
#define SEM2 1
#define SEM3 2
union semun
{
int val;
};
void sem_init();
void sem_p(int index);
void sem_v(int index);
void sem_destory();
(sem.c)
#include "sem.h"
static int semid = -1;
void sem_init()
{
int arr[SEM_MAX] = {1,0,0}; //信号量初始值
semid = semget((key_t)1234,SEM_MAX,IPC_CREAT|IPC_EXCL|O600);
if(semid == -1) //全新创建失败 信号量可能已经存在
{
semid = semget((key_t)1234,SEM_MAX,0600); //全新创建失败 尝试获取已存在的信号量
if(semid == -1) //仍获取失败
{
printf("semget err\n");
return;
}
}
else
{
union semun a;
int i = ;
for( ;i < SEM_MAX;i++)
{
a.val = arr[i];
if(semctl(semid,i,SETVAL,a) == -1)
{
printf("semtcl setval err\n");
}
}
}
}
void sem_p(int index)
{
if(index < 0 || index > SEM_MAX)
{
printf("index err\n");
return;
}
struct sebuf buf;
buf.sem_num = index;
buf.sem_op = -1; //p
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1) == -1)
{
printf("semop p err\n");
}
}
void sem_v(int index)
{
if(index < 0 || index > SEM_MAX)
{
printf("index err\n");
return;
}
struct sebuf buf;
buf.sem_num = index;
buf.sem_op = 1; //v
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1) == -1)
{
printf("semop v err\n");
}
}
void sem_destory()
{
if(semctl(semid,0,IPC_RMID) == -1)
{
printf("sem destory err\n");
}
}