信号量与互斥量

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

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

猜你喜欢

转载自blog.csdn.net/flf1234567898/article/details/107078682