产生竞争的原因:
对资源的共享访问,包括硬件资源(设备)和软件资源(内存空间)
原则:
尽量减少共享资源的使用,如全局变量等
解决的方法:
通过建立critical section是操作成为原子操作,使同一时间内,只有一个线程操作该段代码。
kernel对不同的情况提供了不同的方法,注意的是,有的方法可以 Go to sleep 的,有的不行!
有的方法会导致执行的线程go to sleep,而有的方法不会。
有的代码是允许sleep的,那就可以使用go to sleep的方法。
但有的代码是不允许sleep的,那就绝对不能go to sleep的方法。
spinlock就是可以用在不允许sleep的代码中的。
Semaphore
头文件<asm/semaphore.h>.
struct semaphore;
初始化 信号量
void sema_init(struct semaphore *sem, int val);
where val is the initial value to assign to a semaphore.
直接声明 互斥量
Thus, a mutex can be declared and initialized with one of the following:
DECLARE_MUTEX(name);
DECLARE_MUTEX_LOCKED(name);
运行时 初始化
void init_MUTEX(struct semaphore *sem);
void init_MUTEX_LOCKED(struct semaphore *sem);
获取信号量
void down(struct semaphore *sem);
int down_interruptible(struct semaphore *sem);
int down_trylock(struct semaphore *sem);
用down_interruptible比较多,这样用户可以中断这个函数的执行。
所以一定要对这个函数做返回值的判断,如果返回非零,则表示并没有得到信号量。
返还信号量
void up(struct semaphore *sem);
例子:
struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
for (i = 0; i < scull_nr_devs; i++) {
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
init_MUTEX(&scull_devices[i].sem);
scull_setup_cdev(&scull_devices[i], i);
}
一定要在scull_setpu_cdev之前初始化信号量,否则会出现错误。
读写信号量
这种信号量使用于 有多个读进程,少量写进程。 可以同时有多个读进程一起运行。
头文件 <linux/rwsem.h>
struct rw_semaphore
读操作的信号量获取和释放
void down_read(struct rw_semaphore *sem);
int down_read_trylock(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem);
写操作的信号量获取和释放
void down_write(struct rw_semaphore *sem);
int down_write_trylock(struct rw_semaphore *sem);
void up_write(struct rw_semaphore *sem);
void downgrade_write(struct rw_semaphore *sem);
Completions
这种结构专门用于等待其他任务的完成的。
虽然用信号量也可以达到这个作用,但信号量的效率要低。
struct semaphore sem;
init_MUTEX_LOCKED(&sem);
start_external_task(&sem);
down(&sem);
头文件 <linux/completion.h>
struct completion;
静态声明:
DECLARE_COMPLETION(my_completion);
动态定义:
struct completion my_completion;
/* ... */
init_completion(&my_completion);
等待任务完成:
void wait_for_completion(struct completion *c);
通知任务完成:
void complete(struct completion *c);
void complete_all(struct completion *c);
Spinlock
spinlock是比较特殊的一种锁,它是可以运行在不能sleep的地方的,比如 ISR中。
进入spinlock后,有几点要注意
1. 不能被抢占,这点是自动的,得到spinlock后会自动disable当前处理器的抢占。
2. 不能sleep, 所以需要非常注意得到spinlock后调用的函数。
3. disable 中断。