semaphore 在UNIX系统中是信号量的意思,通常在并发的访问共享资源的时候会用到。并发进程为了访问共享资源,通常会经过如下步骤:
- 测试控制该共享资源的信号的值。
- 如果该信号量值为正,则表示该进程可以使用该资源。这种情况下,该进程会将信号量的值+1处理,表明该已经已经被一个进程使用。
- 反之如果信号量的值为0,则表示当前进程无法使用该资源。那么该进程就进入sleep状态直到控制该资源的信号量的值变成正数。当该经常从sleep被唤醒的时候,会跳到步骤1,尝试重新测试信号量的值。
当一个拥有共享资源的进程处理完他的业务逻辑之后,该共享资源的信号量的值会+1,表明当前这个共享资源再次可用。如果有其他进程需要改共享资源并且处于睡眠状态,此时该进程会被唤醒。
测试信号量值和将信号量的值--的操作必须是一个原子性的操作,这个操作是有操作系统内核实现的。
通常情况下,控制着单个资源的信号量会初始化为1.
信号量在内核中的结构如下
struct semid_ds {
unsigned short semval; // semaphore value, always >= 0
pid_t sempid; // pid for last operation
unsigned short semncnt; // processes awaiting semval>curval
unsigned short semzcnt; // proceses awaiting semval == 0
}
总的来说,就是当信号量值>0,表示可用。但值==0,则不可用,且进程会阻塞进入睡眠状态,但信号量再次可用的时候,阻塞的进程会被唤起重新去获取信号量值。
go语言的Mutex就是基于信号量实现的。不同点是go的协程在首次获取锁失败的时候,不会立即阻塞并睡眠,而是会自旋几次尝试再次获取锁,如果超过的尝试次数还是获取失败,则进入阻塞状态。