信号量简介
信号量 (Semaphore)是表示资源的实体,是一个与队列有关的整形变量,其值仅能由P、V操作来改变。公用信号量常用于实现进程间互斥,初始值通常设为1。私用信号量常用于用于实现进程间同步,初始值通常为0或n
P、V操作
当一个进程想要访问临界区资源时,它必须先执行P原语(系统态下执行的某些具有特定功能的程序段)操作将信号量sem减1。若sem>=0,则可以访问资源,否则进程挂起。当它完成对临界区资源操作后,执行V原语操作将sem加1,以释放资源。
sem初试值为1,所以任意进程执行完P操作后sem值变为0,该进程进入临界区。在此进程执行V操作之前,另一进程想要访问临界区,执行P操作后sem值变为-1,因此该进程阻塞。第一个进程执行V操作后,sem值变为0,从而第二个进程唤醒进入就绪队列。第二个进程执行V操作后,如果没有其它进程申请进入临界区,sem值恢复到初始值1。
生产者消费者问题
生产者-消费者问题是典型的PV操作问题。生产者的任务是生成一定量的数据放到缓冲区,并且重复此过程。消费者的任务会从缓冲区拿走数据,并且重复此过程。关键在于保证生产者不会在缓冲区满时继续生产,消费者不会在缓冲区为空时继续消费。缓冲区满时,生产者进程需要阻塞。缓冲区为空时,消费者进程需要阻塞。并且消费者生产这不能同时访问缓冲区。
信号量empy判断生产者是否还可以生产,信号量full判断是否还可以消费,信号量mutex用于互斥访问缓冲区。empty、full是私用信号量,用于进程同步,mutex是公用信号量,用于进程互斥。
//生产者进程
producer:
生产产品;
p(empty); //空的时候信号量empty为缓冲区大小
p(mutex);
送产品进入缓冲区
v(mutex);
v(full); //满的时候信号量0
//消费者进程
consumer:
p(full);
p(mutex);
从缓冲区取走产品
v(mutex);
v(empty);
消费产品;
C语言在Linux下的实现
创建PRODUCE个线程模拟生产者,CONSUMER个线程模拟消费者,一个数组模拟缓冲区情况。
宏定义(全局变量)
#define PRODUCER 4 //生产者数量
#define CONSUMER 4 //消费者数量
#define BUFFER 8 //缓冲区大小
int producer_id