Chinaunix首页 | 论坛 | 博客
  • 博客访问: 154879
  • 博文数量: 24
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 225
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-09 13:04
个人简介

人若是没有理想,那跟咸鱼有什么区别!

文章分类

全部博文(24)

文章存档

2018年(1)

2017年(2)

2016年(8)

2015年(11)

2014年(2)

我的朋友

分类: LINUX

2017-08-24 14:22:11

参考链接如下:


在apue的介绍里,信号量(semaphore)是一个计数器,用于多进程、多线程对共享数据的访问。为了获取共享资源,进程需要执行下列步骤:
    1.测试控制该资源的信号量。
    2.若此信号量的值为正,则进程可以使用该资源。进程将信号量值减1,表示它使用了一个资源单位。
    3.若此信号量的值为0,则进程进入休眠状态,直至信号量的值大于0 。进程被唤醒后,返回到 1 操作。
上述操作中的信号量增、减操作都是原子操作。可以使用下述流程图来表述信号量的使用。


    在使用信号量集合时,需要先进行创建,之后需要对创建好的信号量集合进行控制设置。控制函数使用semctl:

点击(此处)折叠或打开

  1. int semctl(int semid, int semnum, int cmd, ... /*arg*/);
  2. semid : 创建信号量集合时的id号。
  3. semnum : 需要控制的信号量集合的下标号。 (0----N)
  4. cmd    : 参考下表。也可以参考apue。
  5. args    :    这个参数是一个联合体形式。 
  6.     
    union semun {
        int val;               /* used for SETVAL only */
        struct semid_ds *buf;  /* used for IPC_STAT and IPC_SET */
        ushort *array;         /* used for GETALL and SETALL */
    };
    cmd Effect
    SETVAL Set the value of the specified semaphore to the value in the val member of the passed-in union semun.
    GETVAL Return the value of the given semaphore.
    SETALL Set the values of all the semaphores in the set to the values in the array pointed to by the array member of the passed-in union semun. The semnum parameter to semctl() isn't used.
    GETALL Gets the values of all the semaphores in the set and stores them in the array pointed to by the array member of the passed-in union semun. The semnum parameter to semctl() isn't used.
    IPC_RMID Remove the specified semaphore set from the system. The semnum parameter is ignored.
    IPC_STAT Load status information about the semaphore set into the struct semid_ds structure pointed to by the buf member of the union semun.

    semctl()函数可以用来根据semnum参数来对指定的信号量进行初始化,通常用在 对 val 值 进行SETVAL操作,赋值为0. 此时使用semop()函数进行信号量获取时,由于信号量值为0,所以会发生等待,直到此val的值被修改成正整数。

点击(此处)折叠或打开

  1. int semop(int semid, struct sembuf *sops, unsigned int nsops);
    进行上面流程图操作时使用 semop 函数。semop()函数执行信号量集合上的操作数组,并且是原子操作。semop函数的参数
    

点击(此处)折叠或打开

  1. /* Members might not be in this */

  2. struct sembuf {
  3.     ushort sem_num;   //集合中信号量对象的下标
  4.     short sem_op;    //操作数,正整数、负整数、0
  5.     short sem_flg;    //操作标识 IPC_NOWAIT、SEM_UNDO等。
  6. };

sem_op 由调用者赋值,通常在P操作时做-1操作,如果此时val的值为0,则会发生等待。做V操作时+1操作,val的值+1,表示释放了一个信号量资源。
sem_op What happens
Negative Allocate resources. Block the calling process until the value of the semaphore is greater than or equal to the absolute value of sem_op. (That is, wait until enough resources have been freed by other processes for this one to allocate.) Then add (effectively subtract, since it's negative) the value of sem_op to the semaphore's value.
Positive Release resources. The value of sem_op is added to the semaphore's value.
Zero This process will wait until the semaphore in question reaches 0.

下面是实例代码.
由于调用了线程创建,编译时需要链接pthread库: gcc sem_fok.c -lpthread -o sem_fok

点击(此处)折叠或打开

  1. /* sem_fork.c */
  2. #include<sys/types.h>
  3. #include<sys/ipc.h>
  4. #include<sys/sem.h>
  5. #include<unistd.h>
  6. #include<stdio.h>
  7. #include<stdlib.h>
  8. #include<pthread.h>

  9. #define DELAY_TIME 3 /*为了突出演示效果,等待几秒*/
  10. #define        THREAD_NUMS    (4)

  11. /*定义联合体*/
  12. union semun
  13. {
  14.     int val;
  15.     struct semid_ds *buf;
  16.     unsigned short *array;
  17. };

  18. /*函数声明*/
  19. int init_sem(int sem_id,int init_value);/*信号量初始化(赋值)函数*/
  20. int del_sem(int sem_id); /*从系统中删除信号量的函数*/
  21. int sem_p(int sem_id); /*P 操作函数*/
  22. int sem_v(int sem_id); /*V 操作函数*/


  23. int sem_p_idx(int sem_id, int idx);/*P 操作函数*/

  24. /*信号量初始化(赋值)函数*/
  25. int init_sem_idx(int sem_id,int idx, int init_value);
  26. /*V 操作函数*/
  27. int sem_v_idx(int sem_id, int idx);
  28. static void thrRunWait(int idx);
  29. static int g_sem_id = 0;


  30. int main(void)
  31. {
  32.     pthread_t pidRun[THREAD_NUMS];
  33.     int i = 0;
  34.     //int sem_id = 0;

  35.     g_sem_id = semget(ftok(".", 'a'), THREAD_NUMS, 0666|IPC_CREAT);
  36.     if(g_sem_id == -1){    //创建失败后,先清空,重新创建
  37.         printf("semget exist!\n");
  38.         g_sem_id = semget(ftok(".", 'a'), 0, 0666);
  39.         if(g_sem_id == -1){
  40.             printf("semget attach failed!\n");
  41.             return -1;
  42.         }
  43.         semctl(g_sem_id, 0, IPC_RMID);

  44.         g_sem_id = semget(ftok(".", 'a'), THREAD_NUMS, 0666|IPC_CREAT);
  45.         if(g_sem_id != -1){
  46.             printf("semget create ok!\n");
  47.             // return -1;
  48.         }
  49.     }
  50.     //    init_sem(sem_id, THREAD_NUMS);
  51.     for(i = 0; i < THREAD_NUMS; i++){
  52.         init_sem_idx(g_sem_id, i, 0);
  53.     }

  54.     for(i = 0; i < THREAD_NUMS; i++){
  55.         pthread_create(&pidRun[i], NULL, (void *)thrRunWait, (void *)i);    
  56.     }
  57.     sleep(5);
  58.     printf("main start V action--\n");
  59.     sem_v_idx(g_sem_id, 3);
  60.     sem_v_idx(g_sem_id, 2);
  61.     sem_v_idx(g_sem_id, 1);
  62.     sem_v_idx(g_sem_id, 0);
  63.     printf("main V action over\n");

  64.     sleep(3);
  65.     return 0;
  66. }/* main() end*/



  67. /*信号量初始化(赋值)函数*/
  68. int init_sem_idx(int sem_id,int idx, int init_value)
  69. {
  70.     union semun sem_union;
  71.     sem_union.val=init_value; /*init_value为初始值*/
  72.     if(semctl(sem_id,idx,SETVAL,sem_union)==-1)
  73.     {
  74.         perror("Initialize semaphore");
  75.         return -1;
  76.     }
  77.     return 0;
  78. }
  79. /*信号量P操作创建线程*/
  80. static void thrRunWait(int idx)
  81. {
  82.     printf("thrRunWait idx:%d waiting---!\n", idx);
  83.     sem_p_idx(g_sem_id, idx);
  84.     printf("thrRunWait idx:%d run over!\n", idx);
  85.     return ;
  86. }

  87. /*信号量初始化(赋值)函数*/
  88. int init_sem(int sem_id,int init_value)
  89. {
  90.     union semun sem_union;
  91.     sem_union.val=init_value; /*init_value为初始值*/
  92.     if(semctl(sem_id,0,SETVAL,0)==-1)
  93.     {
  94.         perror("Initialize semaphore");
  95.         return -1;
  96.     }
  97.     return 0;
  98. }

  99. /*从系统中删除信号量的函数*/
  100. int del_sem(int sem_id)
  101. {
  102.     union semun sem_union;
  103.     if(semctl(sem_id,0,IPC_RMID,sem_union)==-1)
  104.     {
  105.         perror("Delete semaphore");
  106.         return -1;
  107.     }
  108. }

  109. /*P 操作函数*/
  110. int sem_p_idx(int sem_id, int idx)
  111. {
  112.     struct sembuf sem_b;
  113.     sem_b.sem_num=idx; /*信号量编号,这里单个信号量的编号应该为0*/
  114.     sem_b.sem_op=-1; /*信号量操作,取值为-1表示P操作*/
  115.     sem_b.sem_flg=SEM_UNDO; /*在进程没释放信号量而退出时,系统自动释放该进程中未释放的信号量*/
  116.     if(semop(sem_id,&sem_b,1)==-1)    /*进行P操作*/
  117.     {
  118.         perror("P operation");
  119.         return -1;
  120.     }
  121.     return 0;
  122. }

  123. /*V 操作函数*/
  124. int sem_v_idx(int sem_id, int idx)
  125. {
  126.     struct sembuf sem_b;
  127.     sem_b.sem_num=idx; /*信号量编号,这里单个信号量的编号应该为0*/
  128.     sem_b.sem_op=1; /*信号量操作,取值为+1表示V操作*/
  129.     sem_b.sem_flg=SEM_UNDO; /*在进程没释放信号量而退出时,系统自动释放该进程中
  130.                  未释放的信号量*/
  131.     if(semop(sem_id,&sem_b,1)==-1)    /*进行V 操作*/
  132.     {
  133.         perror("V operation");
  134.         return -1;
  135.     }
  136.     return 0;
  137. }
 







阅读(2488) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~