基本概念
信号量是一个计数器,用于为多个进程提供对共享数据对象的访问。
信号量和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; }