信号量与互斥量

    技术2022-07-12  67

    进程间需要进行通信,通信的过程中就会产生很多关系,经典的关系就是生产者消费者模型。 生产者消费者模型: 两个进程共享共享一块公共的固定大小的缓冲区,其中一个是生产者,将信息放入缓冲区;另一个是消费者,用来从缓冲区中读取信息。生产者不断进行生产,如果缓冲区满,生产者进行睡眠,唤醒消费者,否则生产者持续向缓冲区放入数据。消费者从缓冲区拿出数据,如果缓冲区为空的时候,消费者进行休眠,此时唤醒生产者。 这只是理想化模型,如果发给一个未睡眠进程的wakeup信号丢失了,就会导致生产者消费者都会进入休眠状态。

    于是就产生了信号量来解决这些问题,使用一个整型变量来累计唤醒次数,供以后使用。这个新的变量就称为信号量。 一个信号量的取值可以为0(表示没有保存下来的唤醒操作)或者是正值(表示有一个或者多个唤醒操作)。 用信号量解决生产者消费者模型问题,注意信号量要使用一种补补课分割的方式去实现他,通常 sleep 和wakeup都是系统调用实现,操作系统在执行下面操作时暂时屏蔽中断。在多CPU下,每个信号量应该由一个锁变量进行保护。 解决生产者消费者模型问题采用了3个信号量: 1:full用来记录缓冲区槽数目; 2:empty用来记录缓冲区空槽数目; 3:mutex确保生产者和消费者不会同时访问缓冲区; 信号量的读取仅仅是几毫秒,生产者消费者可能是任意时间。 代码是区分这两种实现方式最直观的途径 普通实现生产者消费者模型

    #define N 100//定义这个缓冲区100为满 int count = 0; void producer(void) { int item; while(1) { item = produce_item();//生产数据 if(count == N)//如果满了 { sleep();//进入休眠状态 } else{ insert_item(item);//没有就把新产生的数据放入缓冲区 count = count +1; if(count == 1) { wakeup(consumer); } } }

    信号量实现生产者消费者模型

    #define N 10 typedef int semaphore; //这里信号量本质还是int 只不过是取了个别名 semaphore mutex = 1; semaphore empty = N; semaphore full = 0; void producer(void) { int item; while(1) { item = produce_item(); down(&empty);//空槽数减一 down(&mutex);//进入临界区 insert_item(&item);//放入缓冲区 up(&mutex);//离开临界区 up(&full);//满槽数目加一 } } void consumer(void) { int item; while(1) { down(&full);//满槽数目减一 down(&mutex);//进入临界区 item = remove_item(); up(&mutex);//离开临界区 up(&empty);//空槽数目加一 consume_item(item); } }

    对比这两个,普通实现方案就是生产者一次消费者一次的过程,中间过程没有检验过程,但是相比较信号量实现生产——消费模型,生产消费模型会检验临届区是否有正在进行的进程,并且会记录空槽和满槽的量,相比较而言大大提升了代码的安全性,不会因为某个信号丢失导致崩溃。 互斥量: 互斥量实际上就是信号量的简化版本,不需要进行计数操作 适用区域:管理共享内存的一小段代码, 互斥量有两个状态:加锁和解锁,常常用一个二进制位表示,0表 示解锁,其他值表示加锁。 当线程和进程需要访问临界区的时候,调用Mutex_lock;如果当前互斥量是解锁的,调用成功,调用线程可以自由进入该临界区。 如果互斥量已经加锁,调用线程会被阻塞,直到临届区中所有的线程完成并调用mutex_unlock。多个线程被阻塞在互斥量上,将随机选择一个线程并允许它获得锁。 使用互斥锁用来保护临界区,互斥锁不是强制性的,由程序员来操作。 我们来看互斥量实现生产者消费者模型的代码。

    #include<stdio.h> #include<pthread.h> #define MAX 10000000 pthread_mutex_t the_mutex; pthread_cond_t condc,condp; int buffer = 0; void *producer(void* ptr) { int i; for(i = 1;i < MAX;i++) { pthread_mutex_lock(&the_mutex); while(buffer != 0) { pthread_cond_wait(&condp,&the_mutex); buffer = i; pthread_cond_signal(&condc); pthread_mutex_unlock(&the_mutex); } pthread_exit(0); } } void* consumer(void *ptr) { int i; for(i = 1;i < MAX;i++) { pthread_mutex_lock(&the_mutex); while(buffer == 0) { pthread_cond_wait(&condc,&the_mutex); } buffer = 0; pthread_cond_signal(&condp); pthread_mutex_unlock(&the_mutex); } pthread_exit(0); } int main(int argc,char* argv[]) { pthread_t pro,con; pthread_mutex_init(&the_mutex,0); pthread_cond_init(&condp,0); pthread_cond_init(&condc,0); pthread_create(&con,0,consumer,0); pthread_create(&pro,0,producer,0); pthread_join(pro,0); pthread_join(pro,0); pthread_cond_destroy(&condc); pthread_cond_destroy(&condp); pthread_mutex_destroy(&the_mutex); }

    非常清晰看到在这个实现中,生产者消费者模型使用了加锁解锁,大大提升了安全性。

    Processed: 0.013, SQL: 10