标签:
信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语。有三种类型:Posix有名信号量,使用Posix IPC名字标识;Posix基于内存的信号量,存放在共享内存区中;System V信号量,在内核中维护。这三种信号量都可用于进程间或线程间的同步。
图1 由两个进程使用的一个二值信号量
图2 由两个进程使用的一个Posix有名二值信号量
图3 由一个进程内的两个线程共享的基于内存的信号量
一个进程可以在某个信号量上执行的三种操作:
1、创建一个信号量,这要求调用者指定初始值,对于二值信号量来说,它通常是1,也可是0。
2、等待一个信号量,该操作会测试这个信号量的值,如果小于0,就阻塞。也称为P操作。
3、挂出一个信号量,该操作将信号量的值加1,也称为V操作。
信号量、互斥锁和条件变量之间的三个差异:
1、互斥锁必须总是给它上锁的线程解锁,信号量的挂出却不必由执行过它的等待操作的同一线程执行。
2、互斥锁要么被锁住,要么被解开。
3、既然信号量有一个与之关联的状态,那么信号量挂出操作总是被记住。然而当向一个条件变量发送信号时,如果没有线程等待在该条件变量上,信号丢失。
Posix提供两类信号量:有名信号量和基于内存的信号量(也称无名信号量)。使用函数如下:
- #include <semaphore.h>
- sem_t *sem_open(const char *name, int oflag, ...
- int sem_close(sem_t *sem);
- int sem_unlink(const char *name);
- int sem_wait(sem_t *sem);
- int sem_trywait(sem_t *sem);
- int sem_post(sem_t *sem);
- int sem_getvalue(sem_t *sem, int *valp);
semcreate程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <sys/types.h>
-
- #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
-
- int
- main(int argc, char **argv)
- {
- int c, flags;
- sem_t *sem;
- unsigned int value;
-
- flags = O_RDWR | O_CREAT;
- value = 1;
-
- while((c = getopt(argc, argv, "ei:")) != -1){
- switch(c){
- case ‘e‘:
- flags |= O_EXCL;
- case ‘i‘:
- value = atoi(optarg);
- break;
- }
- }
-
- if(optind != argc - 1){
- printf("usage:semcreate [-e] [-i initalvalue] <name>\n");
- return -1;
- }
- sem = sem_open(argv[optind], flags, FILE_MODE, value);
-
- sem_close(sem);
- exit(0);
- }
semunlink程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- int
- main(int argc, char **argv)
- {
- if(argc != 2){
- printf("usage:semunlink <name>.\n");
- return -1;
- }
-
- sem_unlink(argv[1]);
- exit(0);
- }
semgetvalue程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- int
- main(int argc, char **argv)
- {
- sem_t *sem;
- int val;
-
- if(argc != 2){
- printf("usage:semgetvalue <name>.\n");
- return -1;
- }
-
- sem = sem_open(argv[1], 0);
- sem_getvalue(sem, &val);
- printf("value = %d\n", val);
-
- exit(0);
- }
semwait程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- int
- main(int argc, char **argv)
- {
- sem_t *sem;
- int val;
-
- if(argc != 2){
- printf("usage: semwait <name>");
- return -1;
- }
-
- sem = sem_open(argv[1], 0);
- sem_wait(sem);
- sem_getvalue(sem, &val);
- printf("pid %ld has semaphore, value = %d\n", (long)getpid(), val);
-
- pause();
- exit(0);
- }
sempost程序:
- #include <semaphore.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- int
- main(int argc, char **argv)
- {
- sem_t *sem;
- int val;
-
- if(argc != 2){
- printf("usage:sempost <name>\n");
- return -1;
- }
-
- sem = sem_open(argv[1], 0);
- sem_post(sem);
- sem_getvalue(sem, &val);
- printf("value = %d\n", val);
-
- exit(0);
- }
Posix基于内存的信号量,由应用程序分配信号量的内存空间(也就是分配一个sem_t数据类型的内存空间),然后由系统初始化它们的值。
- #include <stmaphore.h>
- int sem_init(sem_t *sem, int shared, unsigned int value);
- int sem_destroy(sem_t *sem); <span style="white-space:pre"> </span>
基于内存的信号量是由sem_init初始化的,sem参数指向应用程序必须分配的sem_t变量。如果shared为0,那么待初始化的信号量是在同一进程的各个线程间共享的,否则该信号量是在进程间共享的。
当不需要使用与有名信号量关联的名字时,可改用基于内存的信号量。彼此无亲缘关系的不同进程需要使用信号量时,通常使用有名信号量。其名字就是各个进程标识信号量的手段。基于内存信号量至少具有进程持续性,然而它们真正的持续性却取决于存放信号量的内存区的类型。只要含有某个基于内存信号量的内存区保持有效,该信号量就一直存在。
进程间共享信号量
进程间共享基于内存信号量的规则很简单:信号量本身必须驻留在由所有希望共享它的进程所共享的内存区中,而且sem_init的第二个参数必须是1。
有名信号量,不同进程总是能够访问同一个有名信号量,只要它们在调用sem_open时指定相同的名字即可。
信号量限制
Posix定义了两个信号量限制:
SEM_NSEMS_MAX 一个进程可同时打开着的最大信号数
SEM_VALUE_MAX 一个信号量的最大值
这两个常值定义在<unistd.h>头文件中,可在运行时通过sysconf函数获取。
linux Posix 信号量
标签:
原文地址:http://www.cnblogs.com/jiangzhaowei/p/4201972.html