Synchronization mechanism

同步机制与原理

进程、线程的同步

先说结论:线程之间的叫同步,进程之间的叫通信。

对于进程来说,由于进程能够通信就意味是同步机制,所以先来说一下进程的同步机制:

  • 信号量:用来实现进程间的同步与互斥,但不能存储通信数据;
  • 消息队列:由链表,存放在内核中并由消息队列标识符标识。
  • 共享内存:能实现内存被多个进程共享;
  • 管道(pipe):半双工的通信方式,单向通信,而且只能在具有亲缘关系的进程间通信;
  • 命名管道:同样半双工,但允许非亲缘关系的进程通信;
  • 信号:通知某个进程事件的发生;
  • 套接字

由于进程有独立的地址空间,所以一般不会有互斥锁这些锁机制,除非是像文件锁这种大锁。而在这种情况下,由于线程共享同一进程下的内存空间,就会有锁机制来保证同步。

而对于线程来讲,主要的同步机制有以下几种:互斥锁,信号量,临界区,条件变量。

同步原理

互斥锁

互斥锁是一种时间和空间代价都比较低廉的,实现对资源互斥访问的手段。主要有两种状态:lock & unlock

当一个线程想要进入临界区操作数据的时候会尝试给它加锁,如果锁已经处于unlock状态,该线程就会被阻塞,直到锁被释放。

条件变量

与互斥锁不同的是,条件变量是自动阻塞进程进入等待状态而不是用来上锁,它会等待某个信号的接收。

通常来说会用互斥锁来保护条件变量,避免多线程竞争条件变量。

另外,互斥锁和条件变量结合可以解决一个互斥锁的问题,就是避免互斥锁频繁地被线程进行加锁和释放锁。

信号量

信号量也是用来保护互斥区的。信号量是一个特殊的变量,程序对信号量的访问都是原子操作的,并且只允许对其进行两种操作P和V。

虽然信号量使得共享资源在一个时间内只有一个线程能够使用,这是二值信号量,但往往,我们可以使用计数信号量,来表明最多允许有多少个持有者。

内核信号量的原型:

1
2
3
4
5
6
7
#include<include\linux\semaphore.h>
struct semaphore
{
   atomic_t count;
   int sleepers;
   wait_queue_head_t wait;
}

与自旋锁不同的是,自旋锁会不断轮询锁的状态,而信号量会因为任务想要的信号量被占用了,只能进入等待队列,并进入睡眠状态(这时处理器可以去处理其它操作)。

所以信号量适用于锁会被长期占用的状态