并发和并行:
并发和并行的区别就是一个处理器同时处理多个任务和多个处理器或者是多核的处理器同时处理多个不同的任务。前者是逻辑上的同时发生(simultaneous),而后者是物理上的同时发生.
并发性(concurrency),又称共行性,是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。
并行(parallelism)是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。
中断屏蔽:
中断屏蔽使得中断与进程之间的并发不再发生,而且,Linux内核的进程调度等操作都依赖中断来实现,内核抢占进程之间的并发也就得以避免了。
local_irq_disable();
.........
//临界区
local_irq_enable();
信号量:
信号量(Semaphore),信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用临界区的进程数。
信号量初始化:
void sema_init(struct semaphore *sem, int val);
一元信号量:
DECLARE_MUTEX(name); //初始值为1 , name为信号量名称
DECLARE_MUTEX_LOCKED(name); //初始化值为0
获得信号量:
void down(struct semaphore *sem);
int down_interruptible(struct semaphore *sem); //操作可中断
int down_trylock(struct semaphore *sem); //永远不会休眠,如果信号量不可获得,立即返回一个非零值
释放信号量:
void up(struct semaphore *sem);
自旋锁:
自旋锁在内核中主要用来防止多处理器中并发访问临界区,防止内核抢占造成的竞争。自旋锁可在不能休眠的代码中使用,比如中断处理例程。
初始化:
spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED;
void spin_lock_init(spinlock_t *lock);
锁定函数:
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsinged long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock);
释放:
void unspin_lock(spinlock_t *lock);
void unspin_lock_irqsave(spinlock_t *lock, unsinged long flags);
void unspin_lock_irq(spinlock_t *lock);
void unspin_lock_bh(spinlock_t *lock);
完成变量(completion):
一种轻量级的机制,它允许一个线程告诉另一个线程某个工作已经完成。
DECLARE_COMPLETION(xxx_completion);
struct completion xxx_completion;
init_completion(&xxx_completion);
void wait_for_completion(struct completion *xxx_completion);
void complete(struct completion *xxx_completion); //只唤醒一个线程
void complete_all(struct completion *xxx_completion); //允许唤醒所有等待的线程
信号量与自旋锁:
信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,自旋锁在内核中主要用来防止多处理器中并发访问临界区,它可以在任何上下文使用。如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。