read_lock()和write_lock()的过程描述如下:
锁变量的初值为RW_LOCK_UNLOCKED(0x01000000),锁变量为正时为未锁状态,反之为上锁状态。
read_lock()对锁变量减1,如果结果为负,则说明已被某个write_lock()上锁。然后read_lock()对锁变量加1,释 放read_lock状态,接着等待锁变量的值变为1;一旦锁变量变为1,read_lock()再次对锁变量减1 ,如果非负则成功,否则重复上述过程。
write_lock()对锁变量减0x01000000,如果结果非零,则说明已被write_lock()或read_lock()上锁。然 后write_lock()对锁变量加0x01000000,释放write_lock()状态,接着等待锁变量的值变为0x01000000;一旦锁变 量变为0x01000000,write_lock()再次对锁变量减0x01000000,如果为零则成功,否则重复上述过程。
read_lock(&mr_rwlock);
write_lock(&mr_rwlock);
deadlocks as the write lock spins, waiting for all readers to release the lockincluding yourself. If you ever need to write, obtain the write lock from the very start. If the line between your readers and writers is muddled, it might be an indication that you do not need to use reader-writer locks. In that case, a normal spin lock is optimal.
执行上面2行代码的进程将阻塞到write_lock(&mr_rwlock); 因为mr_rwlock读锁没有释放
可以多个同时读,但是读-写, , 写-写 都是 互斥的
原理和 spin_lock一样
include/linux/spinlock.h 中定义了write_lock,由于不是SMP,所以定义如下 : 就是禁止抢占就够了,不会被别人抢到锁
#define _write_lock(lock) /
do { /
preempt_disable(); /
_raw_write_lock(lock); /
__acquire(lock); /
} while(0)
#define _raw_write_lock(lock) do { (void)(lock); } while(0)
arm代码 (自由CONFIG_SMP时候才会用到)
static inline void _raw_spin_lock(spinlock_t *lock)
{
unsigned long tmp;
igned long tmp, tmp2;
__asm__ __volatile__(
"1: ldrex %0, [%2]/n"
" adds %0, %0, #1/n"
" strexpl %1, %0, [%2]/n"
" rsbpls %0, %1, #0/n"
" bmi 1b"
: "=&r" (tmp), "=&r" (tmp2)
: "r" (&rw->lock)
: "cc", "memory");
}
static inline void _raw_write_lock(rwlock_t *rw)
{
unsigned long tmp;
__asm__ __volatile__(
"1: ldrex %0, [%1]/n"
" teq %0, #0/n"
" strexeq %0, %2, [%1]/n"
" teq %0, #0/n"
" bne 1b"
: "=&r" (tmp)
: "r" (&rw->lock), "r" (0x80000000)
: "cc", "memory");
}
static inline void _raw_read_lock(rwlock_t *rw)
{
unsigned long tmp, tmp2;
__asm__ __volatile__(
"1: ldrex %0, [%2]/n"
" adds %0, %0, #1/n"
" strexpl %1, %0, [%2]/n"
" rsbpls %0, %1, #0/n"
" bmi 1b"
: "=&r" (tmp), "=&r" (tmp2)
: "r" (&rw->lock)
: "cc", "memory");
}
都是用
原子操作指令
原子操作和以上也类似 :
static inline void atomic_set(atomic_t *v, int i)
{
unsigned long tmp;
__asm__ __volatile__("@ atomic_set/n"
"1: ldrex %0, [%1]/n"
" strex %0, %2, [%1]/n"
" teq %0, #0/n"
" bne 1b"
: "=&r" (tmp)
: "r" (&v->counter), "r" (i)
: "cc");
}