Linux 信号量

信号量

信号量主要用于进程和线程间的同步,信号量保存一个整数值来控制对资源的访问,当值大于0时,表示资源空闲可以访问,等于0时表示资源分配完毕无法访问,小于0时表示有至少1个线程(进程)正在等待资源。如果信号量的值只为0或1,那么它就是一个二元信号量,功能就想当于一个互斥锁。

信号量的P,V操作

信号量只有两种操作:等待和发送信号,分别用P(s), V(s)表示。P,V操作是不可分割的。

P(s): 如果s的值大于0,那么P将s的值减1。如果s为0,那么就挂起这个线程知道s变为非零。一个V操作会唤醒这个线程。

V(s):将s加1,如果有线程等待s变为非0,那么唤醒该线程,该线程将s减1。

函数解析

信号量有两种实现:System V信号量和Posix信号量,System V信号量由semget、semop、semctl这几个函数来实现,具体参考: System V信号量函数。下面重点介绍Posix的信号量函数。

#include<semaphore.h>    包含在头文件
int sem_init(sem_t *sem, int pshared, unsigned int value)
    sem:要初始化的信号量;
    pshared:此信号量是在进程间共享还是线程间共享,0则为线程共享;
    value:信号量的初始值;
    成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值

int sem_destroy(sem_t *sem)
    sem是要销毁的信号量。
    只有用sem_init初始化的信号量才能用sem_destroy销毁。
    成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值

int sem_wait(sem_t *sem)
    等待信号量,如果信号量的值大于0,将信号量的值减1,立即返回。
    如果信号量的值为0,则线程阻塞。相当于P操作。
    成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值

int sem_post(sem_t *sem)
    释放信号量,让信号量的值加1。相当于V操作。
    成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值

Linux线程的信号量同步

信号量处理生产者消费者问题

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

struct buffer
{
  char data[20];
  int n;  //number of product in data
  int p; //index of producer
  int c; //index of consumer
  buffer():n(20),p(-1),c(-1){}
};

int bk = 1;
buffer mybuf;
sem_t mutex, prod, cons;  // three semaphore 

void* producer_thread(void* arg)
{
  char ch = 'A';
  while(bk)
  {
    sem_wait(&prod);    //can produce
    sem_wait(&mutex);  //mutex the buff
    mybuf.data[(++mybuf.p)%mybuf.n] = ch;
    sem_post(&mutex);
    sem_post(&cons);   //tell consumer there is new product
    printf("%lu produce: %c\n", pthread_self(), ch);
    if(ch>='Z')
      ch = 'A';
    else
      ch = ch + 1;
    sleep(1);   //relax
  }
  return NULL;
}

void* consumer_thread(void* arg)
{
  char ch;
  while(bk)
  {
    sem_wait(&cons);  //wait for product 
    sem_wait(&mutex);
    ch = mybuf.data[(++mybuf.c)%mybuf.n];
    sem_post(&mutex);
    sem_post(&prod);  //tell producer there is a new buff to produce
    printf("%lu consume: %c\n", pthread_self(), ch);
    sleep(2);  //digest
  }
  return NULL;
}

int main()
{
  pthread_t pidp[5];
  pthread_t pidc[5];
  sem_init(&mutex, 0, 1);
  sem_init(&cons, 0, 0);    //at the begin there is 0 product ot consume
  sem_init(&prod, 0, 20);   //at the begin there are 20 product to produce

  for(int i=0; i<3; i++)
    pthread_create(&pidp[i], NULL, producer_thread, NULL);

  for(int i=0; i<3; i++)
    pthread_create(&pidc[i], NULL, consumer_thread, NULL);

  sleep(10);
  bk = 0;   //after 60s, stop the will
  int x = 3;
  while(x)
  {
    sem_post(&prod);
    printf("prod----\n");
    x--;
  }
  x = 3;
  while(x)
  {
    printf("cons----\n");
    sem_post(&cons);
    x--;
  }

  for(int i=0; i<3; i++)
    pthread_join(pidp[i], NULL);

  for(int i=0; i<3; i++)
    pthread_join(pidc[i], NULL);

  sem_destroy(&mutex);
  sem_destroy(&cons);
  sem_destroy(&prod);
  printf("finished\n");
  return 0;
}

信号量实现生产者消费者问题

信号量与互斥锁条件变量的区别

信号量与线程锁、条件变量相比有以下几点不同:
1. 锁必须是同一个线程获取以及释放,否则会死锁。而条件变量和信号量则不必。
2. 信号的递增与减少会被系统自动记住,系统内部有一个计数器实现信号量,不必担心会丢失,而唤醒一个条件变量时,如果没有相应的线程在等待该条件变量,这次唤醒将被丢失。
3. 信号量可以允许多个线程访问资源,互斥锁一个时刻只有一个线程访问资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值