Chinaunix首页 | 论坛 | 博客
  • 博客访问: 457414
  • 博文数量: 42
  • 博客积分: 1325
  • 博客等级: 中尉
  • 技术积分: 1312
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-13 18:00
个人简介

呵~~~呵~~~

文章分类

全部博文(42)

文章存档

2016年(3)

2015年(1)

2014年(2)

2013年(2)

2012年(7)

2011年(11)

2010年(3)

2009年(13)

我的朋友

分类: LINUX

2015-07-24 15:06:20

在linux下,我们平时所说的信号量,其实是信号量集的操作,可以同时操作若干信号量。网上这方面的文章相当多,但很多文章对其细节操作都语焉不详。下面,我将信号量集的操作函数进行详细描述。

一、函数    
  1. /* 创建信号量集 */
  2. int semget(key_t key, int nsems, int semflg);
  3. return: If successful, the return value will be the semaphore set identifier (a non-negative integer), otherwise -1 is returned, with errno indicating the error.
  4. key:    不再描述。
  5. nsems:  创建的信号量集里面,信号量的个数。
  6. semflg: IPC_CREAT|IPC_EXCL。
  7. 注意:    1. 对nsems>1的信号量集,我们可以理解为一个信号量的数组
  8.         2. 对已创建的信号量集执行semget时,如果nsems和创建时不一致,semget返回-1。

  1. /* 控制信号量集 */
  2. int semctl(int semid, int semnum, int cmd, ...);
  3. semid:   semget返回的。
  4. semnum:  操作单个信号量时,信号量的编号(可理解为信号量数组的下标)。编号从0开始,例如:semget时nsems=3, 那semnum的范围就是0~2。
  5. cmd:     SETVAL IPC_STAT IPC_SET GETALL SETALL IPC_INFO IPC_RMID删除信号量集
  6. arg4:    union semun {                  /* 需要自行定义,内容视cmd参数而定。 */
                   int              val;    /* Value for SETVAL */
                   struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
                   unsigned short  *array;  /* Array for GETALL, SETALL */
                   struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                               (Linux-specific) */
             };
  7. 注意:    1. 当cmd为SETALL/GETALL时,semnum参数失效,函数会将array数组的值逐一赋给每个信号量,并作为单个信号量的初值。当array数组短于信号量数组时,后面的信号量初值=0。长于信号量数组时,以信号量数组长度为准。

  1. /* 操作信号量 */
  2. int semop(int semid, struct sembuf *sops, unsigned nsops);
  3. int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout);
  4. 1. 函数执行操作集中指定的操作(sops->sem_op),增加或者减少信号量的值。
  5.    如果计数小于0(信号量的值是不能小于0的),那么这个信号量就不能再减小,而是会让调用线程/进程阻塞,直到信号量值为0或更大为止
  6. 2. 函数原子地执行在sops中所包含的操作,也就是说:只有在这些操作可以同时成功执行时,这些操作才会被同时执行。
  7. return: If successful semop() and semtimedop() return 0; otherwise they return -1 with errno indicating the error.
  8. semid:  不再描述。
  9. sops:   这个参数实质上是一个结构体指针,这个结构体描述了单个信号量需要进行的操作。
  10.         当需要同时操作多个信号量的时候,可以传入结构体数组。
  11.         struct sembuf {
  12.                unsigned short sem_num;  /* 信号量的编号,类似semctl参数semnum */
                   short          sem_op;   /* 信号量PV操作,eg:=+2 =-1 */
                   short          sem_flg;  /* IPC_NOWAIT and SEM_UNDO */
  13.         }
  14. nsops:  同时进行操作的元素个数,值>=1。简单来说,可以理解为sops指针指向的结构体个数。

二、例程

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>

  4. #include <sys/types.h>
  5. #include <errno.h>

  6. #include <sys/types.h>
  7. #include <sys/ipc.h>
  8. #include <sys/sem.h>

  9. union semun {
  10.     int val;
  11.     struct semid_ds *buf;
  12.     unsigned short *array;
  13. };

  14. int main( int argc, char *argv[])
  15. {
  16.     u_int32_t key = 0xFF00FF00;

  17.     int semhd = semget( key, 3, IPC_CREAT|IPC_EXCL|666);
  18.     if( semhd <= 0) {
  19.         printf("semget fault. %d. %s.\n", semhd, strerror(errno));
  20.         exit(1);
  21.     }

  22.     /* 设置单个信号量 */
  23.     union semun semun_val;
  24.     semun_val.val = 3;
  25.     semctl( semhd, 1, SETVAL, semun_val);

  26.     /* 批量设置信号量 */
  27.     unsigned short val_array[3] = { 5, 6, 7};
  28.     semctl( semhd, 0, SETALL, &val_array[0]);

  29.     printf("%d\n", semctl( semhd, 0, GETVAL, 0));
  30.     printf("%d\n", semctl( semhd, 1, GETVAL, 0));
  31.     printf("%d\n", semctl( semhd, 2, GETVAL, 0));

  32.     /* 信号量PV操作 */
  33.     struct sembuf sops[2];
  34.     sops[0].sem_num = 1;
  35.     sops[0].sem_op = -1;    
  36.     sops[0].sem_flg = SEM_UNDO;

  37.     sops[1].sem_num = 2;
  38.     sops[1].sem_op = -2;
  39.     sops[1].sem_flg = SEM_UNDO;

  40.     semop( semhd, &sops[0], 2);

  41.     printf("%d\n", semctl( semhd, 0, GETVAL, 0));
  42.     printf("%d\n", semctl( semhd, 1, GETVAL, 0));
  43.     printf("%d\n", semctl( semhd, 2, GETVAL, 0));

  44.     semctl( semhd, 0, IPC_RMID);
  45.     return 0;
  46. }

//END

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