一、
1、互斥锁总是必须由给其上锁的线程解锁,信号量的挂出确不必由执行过它的等待操作的同一线程执行。
生产者与消费者伪代码
2、互斥锁要么被锁住,要么被解锁(二值状态,类似于二值信号量)
3、既然信号量有一个与之关联的状态(它的数值),那么信号量的挂出操作总是被记住。然而当向一个条件变量发送信号时,如果没有线程等待在该条件变量上,那么信号将丢失。
ps:提供信号量的原因是,在进程间同步的情况下,若没有涉及到共享内存区时,需要使用信号量。
二、
1、posix提供量中信号量:有名信号量和基于内存的信号量,后者被称为无名信号量。
有名信号量如下图所示:
内存信号量(无名信号量)如下图所示:
三、有名信号量
sem_open:创建一个新的有名信号量或者打开一个已经存在的有名信号量。有名信号量既可用于线程间同步,也可用于进程间同步。
头文件:#include <semaphore.h> 函数原型:sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value); 参数: name 信号量的外部名字 oflag 选择创建或打开一个现有的信号量 mode 权限位 value 信号量初始值
sem_close用于关闭打开着的信号量:
#include <semaphore.h>
int sem_close(sem_t *sem)
sem_unlink将有名信号量从系统中删除
#include <semaphore.h> int sem_unlink(const char *name)
#include <semaphore.h> int sem_wait(sem_t *sem); int sem_trywait(sem_t *sem);
sem_post是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;
#include <semaphore.h>
int sem_post(sem_t *sem);
sem_getvalue,计算机术语,是把 sem 指向的信号量当前值放置在 sval 指向的整数上。 如果有一个或多个进程或线程当前正在使用 sem_wait(3) 等待信号量,POSIX.1-2001 允许返回两种结果在 sval 里:要么返回 0;要么返回一个负值,它的绝对等于当前正在 sem_wait(3) 里阻塞的进程和线程数。Linux 选择了前面的行为(返回零)。
#include <semaphore.h> int sem_getvalue(sem_t *sem,int *sval);
posix有名信号量至少是随内核持续性的,因此可以跨多个进程操作他们。
四、无名信号量
之前的内容处理的是posix有名信号量的内容,这些信号量是由一个name参数标识的,它通常指代文件系统中的某个文件。然而posix也提供了基于内存的信号量。
int sem_init(sem_t *sem, int pshared, unsigned int value);
如果 pshared 是0,那么初始化的信号量是在同一个进程的各个线程间共享的。
如果 pshared 是非零值,那么信号量将在进程之间共享,并且应该定位共享内存区域(见 shm_open(3)、mmap(2) 和 shmget(2))。因为通过 fork(2)
创建的孩子继承其父亲的内存映射,因此它也可以见到这个信号量。所有可以访问共享内存区域的进程都可以用 sem_post(3)、sem_wait(3) 等等操作信号量。
初始化一个已经初始的信号量其结果未定义。 参数 sem :指向信号量对象 pshared : 指明信号量的类型。不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享。 value : 指定信号量值的大小 返回值 sem_init() 成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。 错误 EINVAL value 超过 SEM_VALUE_MAX。 ENOSYS pshared 非零,但系统还没有支持进程共享的信号量。
摧毁信号量:
#include <semaphore.h>
int sem_destroy(sem_t *sem);
进程间共享基于内存信号量的规则:信号量本身(其作为sem_init第一个参数的sem_t数据类型变量)必须驻留在由所有希望共享它的进程所共享的内存区中,而且sem_init的第二个参数必须是1。
在父进程中打开的任何信号量仍应在子进程中打开。如下:
sem_t *sem; sem = sem_open("sem name",O_CREATE|O_EXCL,FILE_MODE,0); if(childpid = fork() == 0) { sem_wait(sem); } else { sem_post(sem); }