1、信号量

(1)概念

信号量和互斥锁(mutex)的区别:互斥锁只允许一个线程进入临界区,而信号量允许多个线程同时进入临界区

不多做解释,要使用信号量同步,需要包含头文件semaphore.h。

主要用到的函数:

  • int sem_init(sem_t *sem, int pshared, unsigned int value);其中sem是要初始化的信号量,pshared表示此信号量是在进程间共享还是线程间共享,value是信号量的初始值。
  • int sem_destroy(sem_t *sem);其中sem是要销毁的信号量。只有用sem_init初始化的信号量才能用sem_destroy销毁。
  • int sem_wait(sem_t *sem);等待信号量,如果信号量的值大于0,将信号量的值减1,立即返回。如果信号量的值为0,则线程阻塞。相当于P操作。成功返回0,失败返回-1。
  • int sem_post(sem_t *sem); 释放信号量,让信号量的值加1。相当于V操作。

(2)举例

《举例1》

 1 /*************************************************************************
 2     > File Name: semTest1.c
 3     > Summary:  信号量实现生产者&消费者模型    
 4     > Author: xuelisheng 
 5     > Created Time: 2018年12月18日 
 6  ************************************************************************/
 7 
 8 #include <stdio.h>
 9 #include <unistd.h>
10 #include <pthread.h>
11 #include <stdio.h>
12 #include <semaphore.h>
13 
14 #define NUM 5
15 
16 int queue[NUM];                                // 全局数组实现环形队列
17 sem_t blank_number, product_number;            // 定义2个信号量:空格子信号量   产品信号量
18 
19 void *producer(void *arg)
20 {
21     int i = 0;
22     while(1)
23     {
24         // int sem_post(sem_t *sem); 释放信号量,让信号量的值加1。相当于V操作。
25         sem_wait(&blank_number);                // 生产者将空格字数 -- ,为0则阻塞等待
26         queue[i] = rand() % 1000 + 1;           // 生产一个产品
27         printf("-----producer-----%d          i = %d\n",queue[i], i);
28         sem_post(&product_number);              // 将产品数 ++   唤醒
29 
30         i = (i+1) % NUM;                        // 借助下标实现环形队列
31         sleep(rand() % 1);                
32     }
33 }
34 
35  void *consumer(void *arg)
36  {
37      int i = 0;
38      while(1)
39      {
40          // int sem_wait(sem_t *sem);等待信号量,如果信号量的值大于0,将信号量的值减1,立即返回。如果信号量的值为0,则线程阻塞。相当于P操作。成功返回0,失败返回-1。
41          sem_wait(&product_number);            // 消费者将产品信号量数 --,为0则阻塞等待
42          printf("-----consumer-----%d         i = %d\n", queue[i], i);
43          queue[i] = 0;                        // 消费一个产品(填充0表示)
44          sem_post(&blank_number);             // 消费掉之后,将格子数 ++
45 
46          i= (i+1) % NUM;
47          sleep(rand() % 3);
48      }
49  }
50 
51  int main()
52  {
53      pthread_t pid, cid;
54 
55      // int sem_init(sem_t *sem, int pshared, unsigned int value);,其中sem是要初始化的信号量,pshared表示此信号量是在进程间共享还是线程间共享(0表示线程),value是信号量的初始值。
56      sem_init(&blank_number, 0, NUM);
57      sem_init(&product_number, 0, 0);
58 
59      pthread_create(&pid, NULL, producer, NULL);
60      pthread_create(&cid, NULL, consumer, NULL);
61 
62      pthread_join(pid, NULL);
63      pthread_join(cid, NULL);
64 
65      // int sem_destroy(sem_t *sem); 其中sem是要销毁的信号量。只有用sem_init初始化的信号量才能用sem_destroy销毁。
66      sem_destroy(&blank_number);
67      sem_destroy(&product_number);
68 
69      return 0;
70  }

运行结果:

-----producer-----384          i = 0
-----consumer-----384         i = 0
-----producer-----778          i = 1
-----producer-----336          i = 2
-----producer-----493          i = 3
-----producer-----422          i = 4
-----producer-----28            i = 0
-----consumer-----778         i = 1
-----producer-----764          i = 1
-----consumer-----336         i = 2
-----producer-----427          i = 2
-----consumer-----493         i = 3
-----producer-----212          i = 3
-----consumer-----422         i = 4
-----producer-----430          i = 4
-----consumer-----28         i = 0
-----producer-----863          i = 0

 

《举例2》

 1 /*************************************************************************
 2     > File Name: semTest2.c
 3     > Summary:  基于信号量的多线程同步,操作系统原理中的P,V操作
 4     > Author: xuelisheng 
 5     > Created Time: 2018年12月18日
 6  ************************************************************************/
 7 #include <pthread.h>
 8 #include <semaphore.h>
 9 #include <unistd.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 
14 /* @Scene: 某行业营业厅同时只能服务两个顾客。
15  * 有多个顾客到来,每个顾客如果发现服务窗口已满,就等待,
16  * 如果有可用的服务窗口,就接受服务。 */
17 
18 /* 将信号量定义为全局变量,方便多个线程共享 */
19 sem_t sem;
20 
21 /* 每个线程要运行的例程 */
22 void * get_service(void *thread_id)
23 {
24     /* 注意:立即保存thread_id的值,因为thread_id是对主线程中循环变量i的引用,它可能马上被修改 */
25     int customer_id = *((int *)thread_id);
26 
27     if(sem_wait(&sem) == 0)                         // 对共享资源的控制(每次只能2个线程对共享资源进行访问)
28     {
29         usleep(100);                /* service time: 100ms */
30         printf("customer %d receive service ...\n", customer_id);
31         sem_post(&sem);
32     }
33 }
34 
35 #define CUSTOMER_NUM 10
36 
37 int main(int argc, char *argv[])
38 {
39     /* 初始化信号量,初始值为2,表示有两个顾客可以同时接收服务 */
40     /* @prototype: int sem_init(sem_t *sem, int pshared, unsigned int value); */
41     /* pshared: if pshared == 0, the semaphore is shared among threads of a process
42      * otherwise the semaphore is shared between processes.   */
43     sem_init(&sem, 0, 2);
44 
45     /* 为每个顾客定义一个线程id, pthread_t 其实是unsigned long int */
46     // 定义10个线程
47     pthread_t customers[CUSTOMER_NUM];
48 
49     int i, ret;
50     /* 为每个顾客生成一个线程 */
51     for(i = 0; i < CUSTOMER_NUM; i++)
52     {
53         int customer_id = i;
54         ret = pthread_create(&customers[i], NULL, get_service, &customer_id);
55         if(ret != 0)
56         {
57             perror("pthread_create");
58             exit(1);
59         }
60         else 
61         {
62             printf("Customer %d arrived.\n", i);
63         }
64         usleep(10);
65     }
66 
67     /* 等待所有顾客的线程结束 */
68     /* 注意:这地方不能再用i做循环变量,因为可能线程中正在访问i的值 */
69     int j;
70     for(j = 0; j < CUSTOMER_NUM; j++)
71      {
72         pthread_join(customers[j], NULL);
73     }
74 
75     /* Only a  semaphore that  has been initialized  by sem_init(3)
76      * should be destroyed using sem_destroy().*/
77     sem_destroy(&sem);
78     return 0;
79 }

运行结果:(结果不唯一)

Customer 0 arrived.
Customer 1 arrived.
customer 0 receive service ...
Customer 2 arrived.
customer 1 receive service ...
Customer 3 arrived.
customer 2 receive service ...
Customer 4 arrived.
customer 3 receive service ...
Customer 5 arrived.
customer 4 receive service ...
Customer 6 arrived.
customer 5 receive service ...
Customer 7 arrived.
customer 6 receive service ...
Customer 8 arrived.
customer 7 receive service ...
Customer 9 arrived.
customer 8 receive service ...
customer 9 receive service ...

 

 

参考:https://www.cnblogs.com/jiqingwu/p/linux_semaphore_example.html

posted on 2018-12-19 17:00  我得去图书馆了  阅读(240)  评论(0编辑  收藏  举报