zoukankan      html  css  js  c++  java
  • 【多线程】使用信号量进行同步【转】

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


    互斥锁和信号量的区别:

    互斥锁:

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

    信号量:

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

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

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

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

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

  • 相关阅读:
    q和blockquote标签的区别
    Python基础数据类型2
    Python基础类型(1)
    Python运算符与编码
    python基础(初识)
    变量,解释器,垃圾回收机制,小整数池总结
    面向对象 --类
    (绑定方法和非绑定方法)类方法,实例方法,静态方法 类属性和实例属性
    logging 模块
    subprocess(cmd命令)模块 && configerparser模块(配置ini文件)
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/5771700.html
Copyright © 2011-2022 走看看