Linux IPCs - Semaphore
Semphore 是linux提供的一种进程间通信机制,可以用于共享资源的互斥以及进程间同步。
1. 资源互斥
互斥的目的是保证资源访问的排它性,和 Mutex 的主要区别如下:
1)Mutex 用于保护具有唯一性的资源,禁止并发访问,多用于Critical section 的保护;
而Semaphore用于保护具有多份的共享资源,限制对同一资源并发访问的数量
2)Mutex 的使用一定遵循谁加锁谁释放的原则,不可以用于进程之间;
而Semaphore 则可以由不同的人来加锁、释放,可以用于进程之间
2. 进程同步
Semaphore 多用于进程之间的同步,协调进程的执行顺序,Linux 包含Posix、System V两种Semaphore。Posix Semaphore 分为有名和无名,无名Semaphore只可以用于进程之内。
3. P\V原语
主要包含P、V原语操作,p操作和v操作是不可中断的程序段,称为原语。P,V原语中P是荷兰语的Passeren,相当于英文的pass,V是荷兰语的Verhoog,相当于英文中的incremnet。
P原语操作的动作是:
(1)S减1;
(2)若S减1后仍大于或等于零,则进程继续执行;
(3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。
V原语操作的动作是:
(1)S加1;
(2)若相加结果大于零,则进程继续执行;
(3)若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。
每一个信号量都会维护一个wait_list
struct semaphore {
raw_spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
P操作,当线程因等待该信号量挂起时,便会插入到这个wait_list的尾部
list_add_tail(&waiter.list, &sem->wait_list);
waiter.task = task;
waiter.up = false;
V操作,如果计数值大于0则将list中的第一个进程取出插入到执行队列里面,等待CPU调度
static noinline void __sched __up(struct semaphore *sem)
{
struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
struct semaphore_waiter, list);
list_del(&waiter->list);
waiter->up = true;
wake_up_process(waiter->task);
}
/**
* try_to_wake_up - wake up a thread
* @p: the thread to be awakened
* @state: the mask of task states that can be woken
* @wake_flags: wake modifier flags (WF_*)
*
* Put it on the run-queue if it's not already there. The "current"
* thread is always on the run-queue (except when the actual
* re-schedule is in progress), and as such you're allowed to do
* the simpler "current->state = TASK_RUNNING" to mark yourself
* runnable without the overhead of this.
*
* Return: %true if @p was woken up, %false if it was already running.
* or @state didn't match @p's state.
*/
也就是说,V操作时被唤醒的进程并不会马上执行,而是要等待下一次CPU调度时,按照优先级调度。并且进程唤醒的是按照阻塞的先后顺序(在wait_list中的顺序)
在使用中测试发现V操作非常的耗时,主要时间应该消耗在线程唤醒上面了