Linux中可以用于进程同步的信号量有两大类,一种是system v标准的semphare,一种是posix中定义semphare,这种又分为两类,一类是named semphare,一类是unnamed semphare。
named semphare
使用
sem_t *sem_open(const char*name, int oflag, mode_t mode, unsigned int value);
创建,并且需要提供sem的name,不相关的进程通过这个那么来引用sem进行同步,kernel 2.6之前Linux只支持unnamed的semphare,named semphare常别创建在虚拟文件系统中,加载与/dev/shm目录下。
unnamed samphare
使用
int sem_init(sem_t *sem, int pshared, unsigned int value);
创建,可以用于同一进程中的不同线程间的同步,也可以用于多个相关进程间的同步(父子进程等)。
system v semphare
使用
int semget(key_t key, int nsems, int semflg);
创建,用于进程间的同步,比较复杂,创建和初始化是分开的,创建是要求提供全局的键值,是多个信号量值的集合。可以创建多个信号量值。使用的资源一定要时候,他是全局的,不然可能导致系统中的可用的semphare个数不足。
======================================
有三种信号量:
1,Posix有名信号量:使用PosixIPC名字标识(通过特定函数,调用一个绝对文件路径名作为参数,返回一个特定标识),可用于进程或线程间通信。
2,Posix基于内存的信号量:存放在共享内存区(进程间共享内存区或者线程间共享内存区),可用于进程或线程间同步。
3,System V信号量:在内核中维护,可用于进程或线程间的同步。
Posix信号量不必在内核中维护的,这不同于systemV信号量。
那么信号量、互斥锁和条件变量之间的差异在哪呢?:
1,互斥锁必须总是由给它上锁的线程解锁,信号量的挂出却不用非得由执行它的等待操作线程执行。
2,互斥锁要么被锁住要么被解开(二值状态,类似于二值信号量)。
下面我们来讲有名信号量:
由于进程间或者线程间同步。
创建或者打开已有的有名信号量:
1 | #include /* For O_* constants */ |
2 | #include /* For mode constants */ |
5 | sem_t *sem_open(const char *name, int oflag); |
6 | sem_t *sem_open(const char *name, int oflag, |
7 | mode_t mode, unsigned int value); |
9 | Link with -lrt or -pthread. |
关闭和删除信号量:3 | int sem_close(sem_t *sem); |
5 | int sem_unlink(const char *name); |
7 | Link with -lrt or -pthread. |
一个进程关闭了之后,内核会自动的对其上打开的的所有有名信号量自动执行关闭,但这并不代表就删除了此信号量。每个信号量都有一个应用计数器记录当前的打开次数,当记录数大于0时,unlink就将其从文件系统中删除,但是其信号的析构要等到最后一个sem_close发生时为止。获取信号量函数:
3 | int sem_wait(sem_t *sem); |
5 | int sem_trywait(sem_t *sem); |
7 | int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); |
9 | Link with -lrt or -pthread. |
测试所指定的信号量值,如果此值等于0,那么线程就投入睡眠中,如果大于0,则将此值减一并返回。释放信号量函数:
3 | int sem_post(sem_t *sem); |
5 | Link with -lrt or -pthread. |
将制定的信号量加一,并唤醒正在等待该信号量值变为正数的所有线程。这里还有一个函数:
3 | int sem_getvalue(sem_t *sem, int *sval); |
5 | Link with -lrt or -pthread. |
通过sval获得当前信号量值,或者通过返回值要么是0,要么是此时阻塞在这个信号量上的进程或者线程数。
下面来讲基于内存的信号量:
3 | int sem_init(sem_t *sem, int pshared, unsigned int value); |
5 | Link with -lrt or -pthread. |
它们由应用程序分配一个信号量的内存空间,然后通过这个函数初始化它。这里,涉及到是进程间共享的还是线程间共享的要分两种看待:
1,进程间共享的:那么应用程序就应该在进程间共享内存区分配一个信号量的内存空间,同时shard的值为nonezero。
2,线程间共享的,那么应用程序就应该在线程间共享内存区分配一个信号量的内存空间,同时shared的值为zero。
释放基于内存的信号量:
3 | int sem_destroy(sem_t *sem); |
5 | Link with -lrt or -pthread. |