【多线程】使用信号量进行同步【转】

本文转载自:http://blog.csdn.net/yusiguyuan/article/details/14110437

 信号量是最早出现的用来解决进程同步与互斥问题的机制(也可实现进程通信),包括一个称为信号量的变量及对它进行的两个原语操作。信号量为一个整数,我们设这个信号量为:sem。很显然,我们规定在sem大于等于零的时候代表可供并发进程使用的资源实体数,sem小于零的时候,表示正在等待使用临界区的进程的个数。根据这个原则,在给信号量附初值的时候,我们显然就要设初值大于零。

p操作和v操作是不可中断的程序段,称为原语。P,V原语中P是荷兰语的Passeren,相当于英文的pass, V是荷兰语的Verhoog,相当于英文中的incremnet。

且在P,V愿语执行期间不允许有中断的发生。

首先应弄清PV操作的含义:PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:

P(S):①将信号量S的值减1,即S=S-1;②如果S>=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。

V(S):①将信号量S的值加1,即S=S+1;②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。

PV操作的意义:我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。

什么是信号量?信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该 信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。

    一般来说,信号量S>=0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;

当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;

若S<=0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。

对信号量有4种操作(include<semaphore>):
1. 初始化(initialize),int set_init(sem_t *sem, int pshared, unsigned int value);//第二参数为0表示进程间不共享
2. 等信号(wait),int sem_wait(sem_t *sem);//信号量大于1时,减一并返回;小于1时线程阻塞。
3. 给信号(signal)int sem_post(sem_t *sem);//信号量加一
4. 清理(destory) int sem_destory(sem_t *sem);

使用信号量实现生产者-消费者例子:

[cpp] view plain copy

  1. #define BUFFER_SIZE 16 // 缓冲区数量
  2. struct prodcons
  3. {
  4. // 缓冲区相关数据结构
  5. int buffer[BUFFER_SIZE]; /* 实际数据存放的数组*/
  6. int readpos, writepos; /* 读写指针*/
  7. sem_t empty; /* 缓冲区非空的条件变量 */
  8. sem_t occupied; /* 缓冲区未满的条件变量 */
  9. sem_t s_put;/*输入互斥信号量*/
  10. sem_t s_take;/*取出互斥信号量*/
  11. };
  12. /* 初始化缓冲区结构 */
  13. void init(struct prodcons *b)
  14. {
  15. b->readpos = 0;
  16. b->writepos = 0;
  17. sem_init(&b->empty,0,BUFFER_SIZE);
  18. sem_init(&b->occupied,0,0);
  19. sem_init(&b->s_put,0,1);//二进制信号量,相当于互斥锁
  20. sem_init(&b->s_take,0,1);
  21. }
  22. /* 将产品放入缓冲区,这里是存入一个整数*/
  23. void put(struct prodcons *b, int data)
  24. {
  25. /*查看空位信号量,是否可以放入产品*/
  26. sem_wait(&b->empty);
  27. /*查看是否有其他线程正在放入,同一时刻只能一个线程放入*/
  28. sem_wait(&b->s_put);
  29. /* 写数据,并移动指针 */
  30. b->buffer[b->writepos] = data;
  31. b->writepos++;
  32. if (b->writepos >= BUFFER_SIZE)
  33. b->writepos = 0;
  34. sem_post(&b->s_put);//解除互斥
  35. sem_post(&b->occupied);//放入完成,被占位置信号量加一
  36. }
  37. /* 从缓冲区中取出整数*/
  38. int get(struct prodcons *b)
  39. {
  40. int data;
  41. /*查看被占信号量,是否有产品可以拿出*/
  42. sem_wait(&b->occupied);
  43. /*查看是否有其他线程正在拿出,同一时刻只能一个线程拿出*/
  44. sem_wait(&b->s_take);
  45. /* 读数据,移动读指针*/
  46. data = b->buffer[b->readpos];
  47. b->readpos++;
  48. if (b->readpos >= BUFFER_SIZE)
  49. b->readpos = 0;
  50. sem_post(&b->s_take);//解除互斥
  51. sem_post(&b->empty);//拿出完成,被空位信号量加一
  52. return data;
  53. }
  54. /* 测试:生产者线程将1 到100 的整数送入缓冲区,消费者线
  55. 程从缓冲区中获取整数,两者都打印信息*/
  56. #define OVER ( - 1)
  57. struct prodcons buffer;
  58. void *producer(void *data)
  59. {
  60. int n;
  61. for (n = 0; n < 100; n++)
  62. {
  63. printf("%d --->\n", n);
  64. put(&buffer, n);
  65. } put(&buffer, OVER);
  66. return NULL;
  67. }
  68. void *consumer(void *data)
  69. {
  70. int d;
  71. while (1)
  72. {
  73. d = get(&buffer);
  74. if (d == OVER)
  75. break;
  76. printf("--->%d \n", d);
  77. }
  78. return NULL;
  79. }
  80. int main(void)
  81. {
  82. pthread_t th_a, th_b;
  83. void *retval;
  84. init(&buffer);
  85. /* 创建生产者和消费者线程*/
  86. pthread_create(&th_a, NULL, producer, 0);
  87. pthread_create(&th_b, NULL, consumer, 0);
  88. /* 等待两个线程结束*/
  89. pthread_join(th_a, &retval);
  90. pthread_join(th_b, &retval);
  91. return 0;
  92. }
  93. <span style="font-family:KaiTi_GB2312;font-size:18px;"><strong>
  94. </strong></span>


互斥锁和信号量的区别:

互斥锁:

  互斥锁是一种保护机制。上锁后其他线程不能进入保护区域的代码,直到锁被释放。

信号量:

  信号量是一种同步机制。信号量的值代表可用的资源数目,当值大于0代表有可用资源,则允许继续操作,否则线程阻塞,等待可用资源。

当可用资源是1时,信号量与互斥锁基本没区别,都起保护作用。当资源数大于1,则当信号量大于0时线程都可进行操作。如果资源大于1时使用互斥锁,则就算资源数大于1时,也只能有一个线程进入操作,其余线程必须阻塞。

信号量可用于进程通信和线程通信,而互斥锁只能用于线程通信。

    但是还是觉得互斥锁就可以认为是信号量的特例。

    现在有种突然明白什么是利用信号量进行多线程同步的含义了。

时间: 2024-12-25 11:45:53

【多线程】使用信号量进行同步【转】的相关文章

细说.NET中的多线程 (五 使用信号量进行同步)

上一节主要介绍了使用锁进行同步,本节主要介绍使用信号量进行同步 使用EventWaitHandle信号量进行同步 EventWaitHandle主要用于实现信号灯机制.信号灯主要用于通知等待的线程.主要有两种实现:AutoResetEvent和ManualResetEvent. AutoResetEvent AutoResetEvent从字面上理解是一个自动重置的时间.举个例子,假设有很多人等在门外,AutoResetEvent更像一个十字旋转门,每一次只允许一个人进入,进入之后门仍然是关闭状态

Linux多线程--使用信号量同步线程【转】

本文转载自:http://blog.csdn.net/ljianhui/article/details/10813469 信号量.同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过是同步的对象不同而已.但是下面介绍的信号量的接口是用于线程的信号量,注意不要跟用于进程间通信的信号量混淆,关于用于进程间通信的信号量的详细介绍可以参阅我的另一篇博文:Linux进程间通信——使用信号量.相似地,线程同步是控制线程执行和访问临界区域的方法. 一.什么是信号量 线程的信号量与进程间通信中

.NET面试题解析(07)-多线程编程与线程同步

系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实是很多的,比如多线程编程.线程上下文.异步编程.线程同步构造.GUI的跨线程访问等等,本文只是从常见面试题的角度(也是开发过程中常用)去深入浅出线程相关的知识.如果想要系统的学习多线程,没有捷径的,也不要偷懒,还是去看专业书籍的比较好. 常见面试题目: 1. 描述线程与进程的区别? 2. 为什么GUI不支持跨线程访问控件?一般如何解决这个问题? 3. 简述后台线程和前台线程的区别? 4. 说说常

Linux多线程--使用互斥量同步线程【转】

本文转载自:http://blog.csdn.net/ljianhui/article/details/10875883 前文再续,书接上一回,在上一篇文章:Linux多线程——使用信号量同步线程中,我们留下了一个如何使用互斥量来进行线程同步的问题,本文将会给出互斥量的详细解说,并用一个互斥量解决上一篇文章中,要使用两个信号量才能解决的只有子线程结束了对输入的处理和统计后,主线程才能继续执行的问题. 一.什么是互斥量 互斥量是另一种用于多线程中的同步访问方法,它允许程序锁住某个对象,使得每次只能

linux程序设计——用信号量进行同步(第十二章)

12.5.2    用互斥量进行同步 另一种在多线程程序中的同步访问方法是使用互斥量.它允许程序员锁住某个对象,使得每次只能有一个线程访问它.为了控制对关键代码的访问,必须在进入这段代码之前锁住一个互斥量,然后在完成操作之后解锁它. 用于互斥量的基本函数和用于信号量的函数非常相似,它们的定义如下所示: #include <pthread.c> int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mu

JAVA笔记14__多线程共享数据(同步)/ 线程死锁 /

/** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两种方法: * 1.同步代码块 * synchronized(要同步的对象){ 要同步的操作 } * 2.同步方法 * public synchronized void method(){ 要同步的操作 } */ public class Main { public static void main(

C++多线程,互斥,同步

C++多线程,互斥,同步 .

Linux多线程编程-信号量

在Linux中,信号量API有两组,一组是多进程编程中的System V IPC信号量:另外一组是我们要讨论的POSIX信号量.这两组接口类似,但不保证互换.POSIX信号量函数都已sem_开头,并不像大多数线程函数那样以pthread_开头,常用的有以下5个: #include <semaphore.h> int sem_init(sem_t* sem, int pshared, unsigned int value); int sem_destroy(sem_t *sem); int se

从头认识多线程-2.15 证明使用属性域作为多线程监视器是不同步的

这一章节接着上一章节最后的错误的思路,我们来证明使用整数属性域作为多线程监视器是不同步的. 1.用同一个属性域作为多线程监视器,是不同步的 package com.ray.deepintothread.ch02.topic_16; /** * * @author RayLee * */ public class DirtyReadWithSynchBlock { public static void main(String[] args) throws InterruptedException

java多线程之线程的同步与锁定(转)

一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. publicclass Foo { privateint x = 100; publicint getX() { return x;     } publicint fix(int y) {         x = x - y; return x;     } } publicclass MyRunnable i