linux进程间信号量

来源:互联网 发布:jsundefined和null知乎 编辑:程序博客网 时间:2024/04/28 20:17

linux进程间信号量

 

  Linux 提供的各种系统调用来实现一个具有两种状态的信号量(binary semaphore)。

 
分配和释放

  和用于分配、释放共享内存的 shmget 和 shmctl 类似,系统调用 semget 和 semctl 负责分配、释放信号量。调用 semget 函数并传递如下参数:一个用于标识信号量组的键值,该组中包含的信号量数量和与 shmget 所需的相同的权限位标识。该函数返回的是信号量组的标识符。您可以通过指定正确的键值来获取一个已经存在的信号量的标识符;这种情况下,传递的信号量组的容量可以为0。
  信号量会一直保存在系统中,甚至所有使用它们的进程都退出后也不会自动被销毁。最后一个使用信号量的进程必须明确地删除所使用的信号量组,来确保系统中不会有太多闲置的信号量组,从而导致无法创建新的信号量组。可以通过调用semctl来删除信号量组。调用时的四个参数分别为信号量组的标识符,组中包含的信号量数量、常量 IPC_RMID 和一个 union semun 类型的任意值(被忽略)。调用进程的有效用户 id 必须与分配这个信号量组的用户 id 相同(或者调用进程为 root 权限亦可)。与共享内存不同,删除一个信号量组会导致 Linux 立即释放资源。
  代码 5.2 展示了用于分配和释放一个二元信号量的函数。
  代码 5.2 (sem_all_deall.c)分配和释放二元信号量
  #include <sys/ipc.h> #include <sys/sem.h> #include <sys/types.h> /* 我们必须自己定义 semun 联合类型。 */ union semun { int val; struct semid_ds *buf; unsigned short int *array; struct seminfo *__buf; }; /* 获取一个二元信号量的标识符。如果需要则创建这个信号量 */ int binary_semaphore_allocation (key_t key, int sem_flags) { return semget (key, 1, sem_flags); } /* 释放二元信号量。所有用户必须已经结束使用这个信号量。如果失败,返回 -1 */ int binary_semaphore_deallocate (int semid) { union semun ignored_argument; return semctl (semid, 1, IPC_RMID, ignored_argument); }

 
初始化信号量

  分配与初始化信号量是两个相互独立的操作。以 0 为第二参数,以 SETALL 为第三个参数调用 semctl 可以对一个信号量组进行初始化。第四个参数是一个 semun 对象,且它的 array 字段指向一个 unsigned short 数组。数组中的每个值均用于初始化该组中的一个信号量。
  代码 5.3 展示了初始化一个二元信号量的函数。
  代码 5.3 (sem_init.c) 初始化一个二元信号量
  #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> /* 我们必须自己定义 union semun。*/ union semun { int val; struct semid_ds *buf; unsigned short int *array; struct seminfo *__buf; }; /* 将一个二元信号量初始化为 1。*/ int binary_semaphore_initialize (int semid) { union semun argument; unsigned short values[1]; values[0] = 1; argument.array = values; return semctl (semid, 0, SETALL, argument); }

 
等待和投递操作

  每个信号量都具有一个非负的值,且信号量支持等待和投递操作。系统调用 semop 实现了这两个操作。它的第一个参数是信号量的标识符,第二个参数是一个包含 struct sembuf 类型元素的数组;这些元素指明了您希望执行的操作。第三个参数是这个数组的长度。 结构体sembuf中包含如下字段:
  sem_num将要执行操作的信号量组中包含的信号量数量。 sem_op是一个指定了操作类型的整数。 如果sem_op是一个正整数,则这个值会立刻被加到信号量的值上。 [BR]如果 sem_op 为负,则将从信号量值中减去它的绝对值。如果这将使信号量的值小于零,则这个操作会导致进程阻塞,直到信号量的值至少等于操作值的绝对值(由其它进程增加它的值)。 [BR]如果 sem_op 为0,这个操作会导致进程阻塞,直到信号量的值为零才恢复。 sem_flg 是一个符号位。指定 IPC_NOWAIT 以防止操作阻塞;如果该操作本应阻塞,则semop调用会失败。如果为sem_flg指定SEM_UNDO,Linux会在进程退出的时候自动撤销该次操作。 代码 5.4 展示了二元信号量的等待和投递操作。
  代码 5.4 (sem_pv.c)二元信号量等待和投递操作
  #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> /* 等待一个二元信号量。阻塞直到信号量的值为正,然后将其减1 */ int binary_semaphore_wait (int semid) { struct sembuf operations[1]; /* 使用(且仅使用)第一个信号量 */ operations[0].sem_num = 0; /* 减一。 */ operations[0].sem_op = -1; /* 允许撤销操作 */ operations[0].sem_flg = SEM_UNDO; return semop (semid, operations, 1); } /* 对一个二元信号量执行投递操作:将其值加一。 这个操作会立即返回。*/ int binary_semaphore_post (int semid) { struct sembuf operations[1]; /* 使用(且仅使用)第一个信号量 */ operations[0].sem_num = 0; /* 加一 */ operations[0].sem_op = 1; /* 允许撤销操作 */ operations[0].sem_flg = SEM_UNDO; return semop (semid, operations, 1); } 指定 SEM_UNDO 标志解决当出现一个进程仍然持有信号量资源时被终止这种特殊情况时可能出现的资源泄漏问题。当一个进程被有意识或者无意识地结束的时候,信号量的值会被调整到“撤销”了所有该进程执行过的操作后的状态。例如,如果一个进程在被杀死之前减小了一个信号量的值,则该信号量的值会增长。

 
调试信号量

  命令 ipcs -s 可以显示系统中现有的信号量组的相关信息。而 ipcrm sem 命令可以从命令行删除一个信号量组。例如,要删除标识符为5790517的信号量组则应运行以下命令:
  % ipcrm sem 5790517
原创粉丝点击