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的有名信号量来同步父子进程的共享内存操作:
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <semaphore.h>
- #include <fcntl.h> /* For O_* constants */
- #include <sys/stat.h> /* For mode constants */
- #include <stdlib.h>
- #define SHM_KEY 0x33
- intmain(int argc, char**argv)
- {
- pid_t pid;
- inti, shmid;
- int*ptr;
- sem_t *sem;
- /* 创建一块共享内存, 存一个int变量 */
- if((shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0600)) == -1) {
- perror("msgget");
- }
- /* 将共享内存映射到进程, fork后子进程可以继承映射 */
- if((ptr = (int *)shmat(shmid, NULL, 0)) == (void*)-1) {
- perror("shmat");
- }
- *ptr = 0;
- /* posix的有名信号量是kernel persistent的
- * 调用sem_unlink删除以前的信号量 */
- sem_unlink("/mysem");
- /* 创建新的信号量, 初值为1, sem_open会创建共享内存
- * 所以信号量是内核持续的 */
- if((sem = sem_open("/mysem", O_CREAT, 0600, 1)) == SEM_FAILED) {
- perror("sem_open");
- }
- if((pid = fork()) < 0) {
- perror("fork");
- } elseif (pid == 0) { /* Child */
- /* 子进程对共享内存加1 */
- for(i = 0; i < 100000; i++) {
- sem_wait(sem);
- (*ptr)++;
- sem_post(sem);
- printf("child: %d\n", *ptr);
- }
- } else{ /* Parent */
- /* 父进程对共享内存减1 */
- for(i = 0; i < 100000; i++) {
- sem_wait(sem);
- (*ptr)--;
- sem_post(sem);
- printf("parent: %d\n", *ptr);
- }
- waitpid(pid);
- /* 如果同步成功, 共享内存的值为0 */
- printf("finally: %d\n", *ptr);
- sem_unlink("/mysem");
- }
- return0;
- }
小结:以上代码在32位机器上可正常编译,但放入64位机器时需要添加<sys/shm.h>头文件,该头文件能根据机器系统类型来决定shmat()的返回,若无<sys/shm.h>头文件,该函数默认返回32位的int类型,故会导致先前说到的错误(这样解释不知对不对,欢迎各位指正)。