System V信号量和Posix信号量区别

时间:2022-09-02 15:11:57
System V信号量和Posix信号量区别
信号量有两种实现:传统的System V信号量和新的POSIX信号量。它们所提供的函数很容易被区分:对于所有System V信号量函数,在它们的名字里面没有划线。例如,应该是semget()而不是sem_get()。然而,所有的的POSIX信号量函数都有一个下划线。下面列出了它们提供的所有函数清单:
Systm V POSIX
semctl() sem_getvalue()
semget() sem_post()
semop() sem_timedwait()
sem_trywait()
sem_wait()
sem_destroy()
sem_init()
sem_close()
sem_open()
sem_unlink()


另外一个区别是,对于POSIX信号量,你可以有命名的信号量,例如,信号量有一个文件
关联它们,
对于最后三个函数,被用来创建,关闭和删除这样一个命名的信号量。
而sem_init()和sem_destroy()仅仅供非命名信号量使用。
他们是有关信号量的两组程序设计接口函数。POSIX信号量来源于POSIX技术规范的实时
扩展方案(POSIX Realtime Extension),常用于线程;system v信号量,常用于进程的同步。
这两者非常相近,但它们使用的函数调用各不相同。前一种的头文件为semaphore.h,函数
调用为sem_init(),sem_wait(),sem_post(),sem_destory()等等。后一种头文件为<sys/sem.h>,
函数调用为semctl(),semget(),semop()等函数。

更详细地请看 man sem_overview

总结:
System V的信号量一般用于进程同步, 且是内核持续的, api为
semget
semctl
semop
Posix的有名信号量一般用于进程同步, 有名信号量是内核持续的. 有名信号量的api为
sem_open
sem_close
sem_unlink

Posix的无名信号量一般用于线程同步, 无名信号量是进程持续的, 无名信号量的api为

sem_init

sem_destroy


下面一个范例使用Posix的有名信号量来同步父子进程的共享内存操作:

C代码  System V信号量和Posix信号量区别  System V信号量和Posix信号量区别
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <semaphore.h>
  5. #include <fcntl.h> /* For O_* constants */
  6. #include <sys/stat.h> /* For mode constants */
  7. #include <stdlib.h>
  8. #define SHM_KEY 0x33
  9. intmain(int argc, char**argv)
  10. {
  11. pid_t pid;
  12. inti, shmid;
  13. int*ptr;
  14. sem_t *sem;
  15. /* 创建一块共享内存, 存一个int变量 */
  16. if((shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0600)) == -1) {
  17. perror("msgget");
  18. }
  19. /* 将共享内存映射到进程, fork后子进程可以继承映射 */
  20. if((ptr = (int *)shmat(shmid, NULL, 0)) == (void*)-1) {
  21. perror("shmat");
  22. }
  23. *ptr = 0;
  24. /* posix的有名信号量是kernel persistent的
  25. * 调用sem_unlink删除以前的信号量 */
  26. sem_unlink("/mysem");
  27. /* 创建新的信号量, 初值为1, sem_open会创建共享内存
  28. * 所以信号量是内核持续的 */
  29. if((sem = sem_open("/mysem", O_CREAT, 0600, 1)) == SEM_FAILED) {
  30. perror("sem_open");
  31. }
  32. if((pid = fork()) < 0) {
  33. perror("fork");
  34. } elseif (pid == 0) { /* Child */
  35. /* 子进程对共享内存加1 */
  36. for(i = 0; i < 100000; i++) {
  37. sem_wait(sem);
  38. (*ptr)++;
  39. sem_post(sem);
  40. printf("child: %d\n", *ptr);
  41. }
  42. } else{ /* Parent */
  43. /* 父进程对共享内存减1 */
  44. for(i = 0; i < 100000; i++) {
  45. sem_wait(sem);
  46. (*ptr)--;
  47. sem_post(sem);
  48. printf("parent: %d\n", *ptr);
  49. }
  50. waitpid(pid);
  51. /* 如果同步成功, 共享内存的值为0 */
  52. printf("finally: %d\n", *ptr);
  53. sem_unlink("/mysem");
  54. }
  55. return0;
  56. }
本人将以上代码放64位机器上编译时报24: cast to pointer from integer of different size的错误,最初认为是int 与pointer在64位机上的大小(前者为4,后者为8)不一样,但本人手动修改后发现依旧,后来翻看手册man shmat后发现丢失头文件<sys/shm.h>,添加后编译OK。
小结:以上代码在32位机器上可正常编译,但放入64位机器时需要添加<sys/shm.h>头文件,该头文件能根据机器系统类型来决定shmat()的返回,若无<sys/shm.h>头文件,该函数默认返回32位的int类型,故会导致先前说到的错误(这样解释不知对不对,欢迎各位指正)。