基本概念
信号量是一个计数器,用于为多个进程提供对共享数据对象的访问。
信号量和P、V原语操作是由Dijkstra(迪杰斯特拉)所提出的。执行P操作时,将该进程状态设置为等待状态,并把
该进程的PCB插入相应的等待队列s.queue末尾;执行V操作时,
唤醒相应等待队列s.queue中等待的一个进程
改变其状态为就绪态
并将其插入就绪队列。
信号量的同步与互斥
互斥:P、V操作在同一个进程中
同步:P、V操作在不同进程中
信号量值含义
当S>0:S表示可用资源的个数;当S=0:表示无可用资源,无等待进程;当S<0:|S|表示等待队列中进程个数
信号量数据结构
struct semid_ds {
struct ipc_perm sem_perm; /* Ownership and permissions */
time_t sem_otime; /* Last semop time */
time_t sem_ctime; /* Last change time */
unsigned short sem_nsems; /* No. of semaphores in set */
};
信号量函数集
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
用来创建和访问一个信号量集,nsems:信号集中信号量的个数
int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, unsigned nsops);
sops是个指向一个结构数值的指针,nsops是信号量的个数。
struct sembuf {
short sem_num;
short sem_op;
short sem_flg;
};
sem_op是信号量一次PV操作时加减的数值,一般只会用到两个值,一个是“-1”,也就是P操作,等待信号量变得可用;另一个是“+1”,也就是我们的V操作,发出信号量已经变得可用
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int sem_open(key_t key)
{
int semid=semget(key,1,0666|IPC_CREAT);
if(semid==-1)
{
printf("semget error!\n");
exit(0);
}
return semid;
}
int sem_setval(int semid,int val)
{
int ret=0;
union semun se;
se.val=val;
ret=semctl(semid,0,SETVAL,se);
return ret;
}
int sem_getval(int semid)
{
int ret=0;
union semun se;
ret=semctl(semid,0,GETVAL,se);
printf("semval is %d\n",se.val);
return ret;
}
int sem_p(int semid)
{
struct sembuf buf= {0,-1,0};
int ret=semop(semid,&buf,1);
return ret;
}
int sem_v(int semid)
{
struct sembuf buf= {0,1,0};
int ret=semop(semid,&buf,1);
return ret;
}
int main(int argc,char*argv[])
{
int semid=sem_open(0x1111);
sem_setval(semid,1);
sem_getval(semid);
sem_p(semid);
printf("hello world!\n");
sem_v(semid);
return 0;
}