信号量主要用于同步和互斥的。
进程互斥:
1:由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程竞争使用这些资源,进程的这种关系就叫做进程互斥
2:系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源
3:在进程中涉及到互斥资源的程序段叫临界区
例如:
进程同步
进程同步指的是多个进程之间相互配合共同完成一项任务
比如我们日常生活中的公交车
司机(进程1)
while(1)
{
启动车辆;
正常运行;
到站停车;
}售票员(进程2)
while(1)
{
关门;
售票;
开门;
}
信号量和P、V原语
信号量:本质上就是一个计数器
信号量值含义
S>0:S表示可用资源的个数
S=0:表示无可用资源,无等待进程
S<0:S的绝对值表示等待队列中的进程个数
信号量结构体伪代码:
struct semaphore
{
int value;
pointer_PCB queue;
}
P、V原语
1、互斥:P、V在同一个进程中
2、同步:P、V在不同的进程中
P原语
P(s)
{
s.value = s.value--;
if(s.value < 0)
{
该进程状态置为等待状态
将该进程的PCB插入相应的等待队列s.queue末尾
}
}
V原语
V(s)
{
s.value = s.value++;
if(s.value >= 0)
{
唤醒相应等待队列s.queue中等待的一个进程
改变其状态为就绪状态
并将其插入就绪队列
}
}
信号量集函数
semget函数:创建和访问一个信号量集
int semget(key_t key,int nsems,int semflg);
//参数:key为信号量集的名字
//nsems为信号集中信号量的个数
//semflg由9个权限标志组成,他们的用法和创建文件时使用的mode模式标志是一样的
//返回值:成功返回一个非负整数,即该信号集的标识码,失败返回-1
semctl函数 :控制信号量集
int semctl(int semid,int semnum,int cmd,...);
//参数:semid由semget返回的信号集标识码
//semnum:信号集中信号量的序号
//cmd:将要采取的动作(有3个可取值)
//最后一个参数根据命令不同而不同
//返回值:成功返回0,失败返回-1
cmd取值
1、SETVAL:设置信号量集中的信号量的计数值
2、GETVAL:获取信号量集中的信号量的计数值
3、 IPC_STAT:把semid结构中的数据设置为信号集的当前关联值
4、IPC_SET:在进程有足够权限的前提下,把信号集的当前关联值设置为semid_ds数据结构中给出的值
5、IPC_RMID:删除信号集
semop函数:创建和访问一个信号量集
int semop(int semid,struct sembuf *sops,unsigned nsops);
//参数:semid是该信号量的表示码,也就是semget函数的返回值
//sops:是一个指向结构体数值的指针
//nsops:信号量的个数
//返回值:成功返回0,失败返回-1
sembuf结构体
struct sembuf
{
short sem_num;
short sem_op;
short sem_flg;
};
1、 sem_num是信号量的编号
2、 sem_op是信号量一次PV操作时加减的数值,一般只会用到两个值:一个是-1,也就是P操作,等待信号量变得可用。另一个是+1,也就是V操作,发出信号量已经变得可用。
3、sem_flg的两个取值是IPC_NOWAIT或SEM_UNDO