Linux编程练习 --多线程5--信号量(semaphore)

时间:2021-05-26 15:16:39

这一篇练习信号量的应用

信号量本质上是一个非负的整数计数器,也是UNIX中古老的实现进程互斥和同步的手段,Linux下信号量概念是在线程中,信号则在进程控制中,不过原理差不多,最基本最经典的操作莫过于P、V操作了,能实现进程、线程的互斥和同步操作,非常值得深入理解。

1.P、V操作原语

 P操作:

 proceduce P(var s:semaphore)

{

  begin

      s:=s-1;

      if(s<0)then W(s);

  end

}

 

V操作:

 proceduce V(var s:semaphore)

{

  begin

      s:=s+1;

      if(s<=0)then R(s);

  end

 

2.基本操作

数据类型:信号量的数据类型为结构sem_t,它本质上是一个长整型的数。

函数:

(1)sem_init

功能:         用于创建一个信号量,并初始化信号量的值。

头文件:       <semaphore.h>

函数原型:     int sem_init (sem_t* sem, int pshared, unsigned int value);

函数传入值:   sem:信号量。

                   pshared:决定信号量能否在几个进程间共享。由于目前LINUX还没有实现进

                               程间共享信息量,所以这个值只能取0。

                   value:初始计算器

函数返回值:   0:成功。

                   -1:失败。

(2)其他函数。

//等待信号量

int sem_wait       (sem_t* sem);

int sem_trywait   (sem_t* sem);

//发送信号量

int sem_post       (sem_t* sem);

//得到信号量值

int sem_getvalue (sem_t* sem);

//删除信号量

int sem_destroy   (sem_t* sem);

功能:sem_wait和sem_trywait相当于P操作,它们都能将信号量的值减一,两者的区别在

        于若信号量的值小于零时,sem_wait将会阻塞进程,而sem_trywait则会立即返回。

        sem_post相当于V操作,它将信号量的值加一,同时发出唤醒的信号给等待的进程

       (或线程)。

        sem_getvalue 得到信号量的值。

        sem_destroy 摧毁信号量。

函数传入值: sem:信号量。

函数返回值: 同上。

好了,了解完基本操作,继续做一个练习:

这里用信号量实现互斥资源访问的功能:

  1. /*sem.c*/  
  2. #include <stdlib.h>    
  3. #include <stdio.h>    
  4. #include <pthread.h>    
  5. #include <semaphore.h>  
  6. #include <errno.h>     
  7. /*全局变量*/  
  8. int gnum = 0;  
  9. /*信号量*/  
  10. sem_t sem;  
  11. /*声明线程运行服务程序*/  
  12. static void pthread_func_1 (void);     
  13. static void pthread_func_2 (void);     
  14.     
  15. int main (void)     
  16. {     
  17.  /*线程的标识符*/  
  18.   pthread_t pt_1 = 0;     
  19.   pthread_t pt_2 = 0;     
  20.   int ret = 0;     
  21.   /*信号量初始化*/  
  22.   sem_init(&sem,0,1);  
  23.   /*分别创建线程1、2*/  
  24.   ret = pthread_create (&pt_1,          //线程标识符指针  
  25.                          NULL,          //默认属性  
  26.                         (void *)pthread_func_1,//运行函数  
  27.                         NULL);          //无参数  
  28.   if (ret != 0)     
  29.   {     
  30.      perror ("pthread_1_create");     
  31.   }     
  32.     
  33.   ret = pthread_create (&pt_2,          //线程标识符指针  
  34.                         NULL,           //默认属性    
  35.                         (void *)pthread_func_2, //运行函数  
  36.                         NULL);          //无参数  
  37.   if (ret != 0)     
  38.   {     
  39.      perror ("pthread_2_create");     
  40.   }     
  41.   /*等待线程1、2的结束*/  
  42.   pthread_join (pt_1, NULL);     
  43.   pthread_join (pt_2, NULL);     
  44.     
  45.   printf ("main programme exit!/n");    
  46.   return 0;     
  47. }     
  48. /*线程1的服务程序*/  
  49. static void pthread_func_1 (void)     
  50. {     
  51.   int i = 0;     
  52.        
  53.   for (;;)     
  54.   {     
  55.     printf ("This is pthread1!/n");      
  56.     sem_wait(&sem);     /*等待信号量*/     
  57.     sleep (1);   
  58.     /*临界资源*/  
  59.     gnum++;  
  60.     printf ("Thread1 add one to num:%d/n",gnum);  
  61.       
  62.     sem_post (&sem);        /*释放信号量*/  
  63.   
  64.        
  65.   }     
  66. }     
  67. /*线程2的服务程序*/   
  68. static void pthread_func_2 (void)     
  69. {     
  70.   int i = 0;     
  71.     
  72.   for (;;)     
  73.   {     
  74.     printf ("This is pthread2!/n");   
  75.     sem_wait(&sem);     /*等待信号量*/  
  76.     sleep (1);  
  77.     /*临界资源*/  
  78.     gnum++;  
  79.     printf ("Thread2 add one to num:%d/n",gnum);  
  80.       
  81.     sem_post (&sem);        /*释放信号量*/  
  82.     
  83.   }     
  84.     
  85.   pthread_exit (0);     
  86. }    

编译,运行,可以看出和上次互斥锁结果一样的