Linux线程编程 - 线程同步机制之信号量

原创 2016年08月29日 10:02:57

 信号量既可以作为二值计数器(即0,1),也可以作为资源计数器. 
  信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。当公共资源增加时,调用函数sem_post()增加信号量。只有当信号量值大于0时,才能使用公共资源,使用后,函数sem_wait()减少信号量。函数sem_trywait()和函数pthread_ mutex_trylock()起同样的作用,它是函数sem_wait()的非阻塞版本。下面我们逐个介绍和信号量有关的一些函数,它们都在头文件 /usr/include/semaphore.h中定义。 
  信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为: 

extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value)); 

  sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。 

而函数int sem_getvalue(sem_t *sem, int *sval);则用于获取信号量当前的计数. 函数sem_destroy(sem_t *sem)用来释放信号量sem。 
可以用信号量模拟锁和条件变量: 

  1. 锁,在同一个线程内同时对某个信号量先调用sem_wait再调用sem_post, 两个函数调用其中的区域就是所要保护的临界区代码了,这个时候其实信号量是作为二值计数器来使用的.不过在此之前要初始化该信号量计数为1,见下面例子中的代码. 
  2. 条件变量,在某个线程中调用sem_wait, 而在另一个线程中调用sem_post. 

  不过, 信号量除了可以作为二值计数器用于模拟线程锁和条件变量之外, 还有比它们更加强大的功能, 信号量可以用做资源计数器, 也就是说初始化信号量的值为某个资源当前可用的数量, 使用了一个之后递减, 归还了一个之后递增。 
  信号量与线程锁,条件变量相比还有以下几点不同: 

  1. 锁必须是同一个线程获取以及释放, 否则会死锁.而条件变量和信号量则不必. 
  2. 信号的递增与减少会被系统自动记住, 系统内部有一个计数器实现信号量,不必担心会丢失, 而唤醒一个条件变量时,如果没有相应的线程在等待该条件变量, 这次唤醒将被丢失. 
复制代码
/*
* =====================================================================================
*
* Filename: pthread4.c
*
* Description: A program of Semaphore
*
* Version: 1.0
* Created: 03/13/2009 11:54:35 PM
* Revision: none
* Compiler: gcc
*
* Author: Futuredaemon (BUPT), gnuhpc@gmail.com
* Company: BUPT_UNITED
*
* =====================================================================================
*/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <semaphore.h>
#define BUFSIZE 4
#define NUMBER 8
int sum_of_number=0;
/* 可读 和 可写资源数*/
sem_t write_res_number;
sem_t read_res_number;
/* 循环队列 */
struct recycle_buffer{
  int buffer[BUFSIZE];
  int head,tail;
}re_buf;
/* 用于实现临界区的互斥锁,我们对其初始化*/
pthread_mutex_t buffer_mutex=PTHREAD_MUTEX_INITIALIZER;
static void *producer(void * arg)
{
  int i;
  for(i=0;i<=NUMBER;i++)
  {
    /* 减少可写的资源数 */
    sem_wait(&write_res_number);
    /* 进入互斥区 */
    pthread_mutex_lock(&buffer_mutex);
    /*将数据复制到缓冲区的尾部*/
    re_buf.buffer[re_buf.tail]=i;
    re_buf.tail=(re_buf.tail+1)%BUFSIZE;
    printf("procuder %d write %d./n",(int)pthread_self(),i);
    /*离开互斥区*/
    pthread_mutex_unlock(&buffer_mutex);
    /*增加可读资源数*/
    sem_post(&read_res_number);
  }
  /* 线程终止,如果有线程等待它们结束,则把NULL作为等待其结果的返回值*/
  return NULL;
}
static void * consumer(void * arg)
{
  int i,num;
  for(i=0;i<=NUMBER;i++)
  {
    /* 减少可读资源数 */
    sem_wait(&read_res_number);
    /* 进入互斥区*/
    pthread_mutex_lock(&buffer_mutex);
    /* 从缓冲区的头部获取数据*/
    num = re_buf.buffer[re_buf.head];
    re_buf.head = (re_buf.head+1)%BUFSIZE;
    printf("consumer %d read %d./n",pthread_self(),num);
    /* 离开互斥区*/
    pthread_mutex_unlock(&buffer_mutex);
    sum_of_number+=num;
    /* 增加客写资源数*/
    sem_post(&write_res_number);
  } 
  /* 线程终止,如果有线程等待它们结束,则把NULL作为等待其结果的返回值*/
  return NULL;
}
int main(int argc,char ** argv)
{
  /* 用于保存线程的线程号 */
  pthread_t p_tid;
  pthread_t c_tid;
  int i;
  re_buf.head=0;
  re_buf.tail=0;
  for(i=0;i<BUFSIZE;i++)
    re_buf.buffer[i] =0;
  /* 初始化可写资源数为循环队列的单元数 */
  sem_init(&write_res_number,0,BUFSIZE); // 这里限定了可写的bufsize,当写线程写满buf时,会阻塞,等待读线程读取
  /* 初始化可读资源数为0 */
  sem_init(&read_res_number,0,0);
  /* 创建两个线程,线程函数分别是 producer 和 consumer */
  /* 这两个线程将使用系统的缺省的线程设置,如线程的堆栈大小、线程调度策略和相应的优先级等等*/
  pthread_create(&p_tid,NULL,producer,NULL);
  pthread_create(&c_tid,NULL,consumer,NULL);
  /*等待两个线程完成退出*/
  pthread_join(p_tid,NULL);
  pthread_join(c_tid,NULL);
  printf("The sum of number is %d/n",sum_of_number);
}
复制代码
版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux进程同步之POSIX信号量

POSIX信号量是属于POSIX标准系统接口定义的实时扩展部分。在SUS(Single UNIX Specification)单一规范中,定义的XSI IPC中也同样定义了人们通常称为System V...
  • anonymalias
  • anonymalias
  • 2013年07月01日 22:14
  • 10536

Linux多线程——使用信号量同步线程

信号量、同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过是同步的对象不同而已。但是下面介绍的信号量的接口是用于线程的信号量,注意不要跟用于进程间通信的信号量混淆。相似地,线程同步...
  • ljianhui
  • ljianhui
  • 2013年09月01日 00:09
  • 44055

linux c 线程间同步(通信)的几种方法--互斥锁,条件变量,信号量,读写锁

Linux下提供了多种方式来处理线程同步,最常用的是互斥锁、条件变量、信号量和读写锁。 下面是思维导图: 一、互斥锁(mutex)   锁机制是同一时刻只允许一个线程执行一个关键部分的代码。1 ...
  • vertor11
  • vertor11
  • 2017年02月18日 11:48
  • 2042

Linux多线程编程入门-同步机制-信号量

int sem_init(sem_t *sem, int pshared, unsigned int value); pshared:控制信号量的类型,0表示这个信号量是当前进程的局部信号量,否则,这...
  • a304672343
  • a304672343
  • 2013年12月03日 11:59
  • 520

线程同步机制:互斥量、信号量、读写锁、条件变量

一、互斥量(mutex)   互斥量本质上是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。   对互斥量进行加锁以后,任何其它试图再次对互斥量加锁的线程将会被阻塞...
  • u010229420
  • u010229420
  • 2015年03月07日 17:19
  • 605

线程同步机制(1)---无名信号量

#include #include #include #include #include #include #include sem_t semR,semW; /...
  • lanxuewen
  • lanxuewen
  • 2014年01月01日 16:04
  • 376

Linux线程编程 - 线程同步机制之互斥锁

互斥锁基本原理 互斥以排他方式防止共享数据被并发修改。互斥锁是一个二元变量,其状态为开锁(允许0)和上锁(禁止1),将某个共享资源与某个特定互斥锁绑定后,对该共享资源的访问如下操作: (1)在访问该...
  • ygl840455828ygl
  • ygl840455828ygl
  • 2016年08月26日 16:43
  • 220

linux下多线程同步机制之信号量、互斥量、读写锁、条件变量

之前有写过类似的博客,这东西不用老忘,现在又有更清晰的理解了。 一、信号量 信号量最基本的两个操作就是PV操作:P()操作实现信号量减少,V()操作实现信号量的增加 信号量的值取决于信号量的类型,信号...
  • ylf13
  • ylf13
  • 2013年10月29日 16:39
  • 6167

【Linux】深入理解线程(线程同步、互斥量mutex、死锁、读写锁、条件变量、信号量)

一、同步概念        1、线程同步:             同步即协同步调,按预定的先后次序运行。             线程同步,只一个线程发出某一功能调用时,在没有得到...
  • kwame211
  • kwame211
  • 2018年01月14日 12:28
  • 40

【Linux】线程总结:线程同步 -互斥锁,条件变量,信号量实现多生产者多消费者模型

学习环境 :  Centos6.5 Linux 内核 2.6 Linux线程部分总结分为两部分:(1)线程的使用 ,(2)线程的同步与互斥。 第一部分线程的使用主要介绍,线程的概念,创建线程...
  • a1414345
  • a1414345
  • 2017年07月19日 21:23
  • 432
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux线程编程 - 线程同步机制之信号量
举报原因:
原因补充:

(最多只允许输入30个字)