互斥:是指散布在不同进程之间的若干程序片段,当某个进程执行其中的一个程序片段时,其他进程就不能运行它们之中的任一程序片段,只能等到该进程运行完之后才可以继续运行。
同步:是指散布在不同进程之间的若干程序片段,它们的运行必须严格按照一定的先后次序来运行,这种次序依赖于要完成的任务
内核中的同步问题一般都是通过 “完成量 completion” 解决
Completion在内核中的实现基于等待队列
/* * struct completion - structure used to maintain state for a "completion" * * This is the opaque structure used to maintain the state for a "completion". * Completions currently use a FIFO to queue threads that have to wait for * the "completion" event. * * See also: complete(), wait_for_completion() (and friends _timeout, * _interruptible, _interruptible_timeout, and _killable), init_completion(), * reinit_completion(), and macros DECLARE_COMPLETION(), * DECLARE_COMPLETION_ONSTACK(). */ struct completion { unsigned int done; wait_queue_head_t wait; };
初始化:
static inline void init_completion(struct completion *x) { x->done = 0; init_waitqueue_head(&x->wait); }
两种初始化都将用于同步的done原子量置位了0,后面我们会看到,该变量在wait相关函数中减一,在complete系列函数中加一
static inline long __sched __wait_for_common(struct completion *x, long (*action)(long), long timeout, int state) { might_sleep(); spin_lock_irq(&x->wait.lock); timeout = do_wait_for_common(x, action, timeout, state); spin_unlock_irq(&x->wait.lock); return timeout; }
static inline long __sched do_wait_for_common(struct completion *x, long timeout, int state) { if (!x->done) { DECLARE_WAITQUEUE(wait, current); wait.flags |= WQ_FLAG_EXCLUSIVE; __add_wait_queue_tail(&x->wait, &wait); do { if (signal_pending_state(state, current)) { timeout = -ERESTARTSYS; break; } __set_current_state(state); spin_unlock_irq(&x->wait.lock); timeout = schedule_timeout(timeout); spin_lock_irq(&x->wait.lock); } while (!x->done && timeout); __remove_wait_queue(&x->wait, &wait); if (!x->done) return timeout; }
// 就是相当于 拿到资源 将done 减一 复位 x->done--; return timeout ?: 1; }
void complete(struct completion *x) { unsigned long flags; spin_lock_irqsave(&x->wait.lock, flags); x->done++; __wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL); spin_unlock_irqrestore(&x->wait.lock, flags); }
可以看到 对done 资源的判断 必须使用 lock 防止资源竞争!!!
也就是如果 wait-done; 判断done 条件,如果不满足,加入等待队列,再次检测是否获取到资源, 没有获取到,释放un-lock, 调度休眠
如果notify -done; 首先lock, 然后唤醒等待队列中等待资源的进程, 释放锁-unlock,让唤醒的进程去加锁拿去资源
再来看一看 用户态的 同步问题:
- 生产者和消费者中存在有同步关系,需要使用pthread_cond_wait和pthread_cond_signal解决
- 生产者和消费者中存在有互斥关系,需要使用pthread_mutex_lock和pthread_mutex_unlock解决
进程A: pthread_mutex_lock(&mutex); while (condition == FALSE) pthread_cond_wait(&cond, &mutex);
process---so-on pthread_mutex_unlock(&mutex); 进程B:
process-so-on pthread_mutex_lock(&mutex); condition = TRUE; pthread_mutex_unlock(&mutex); pthread_cond_signal(&cond);
问什么除了cond 还要有 mutex? 因为一但有多个线程同时操作这个Conditional Variable,就不可避免会出现Race Condition; mutex是为了 condition 同时只能被一个线程拥有
其实 pthread_cond_wait/signal 底层实现 和内核完成量 complete应该差不多!!
其mutex作用可以看:http://blog.sina.com.cn/s/blog_967817f20101bsf0.html
对于 __pthread_cond_wait_common 底层实现 就不看了 没时间 觉得没意义