Chinaunix首页 | 论坛 | 博客
  • 博客访问: 241229
  • 博文数量: 43
  • 博客积分: 1878
  • 博客等级: 上尉
  • 技术积分: 457
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-02 11:08
文章分类

全部博文(43)

文章存档

2011年(3)

2010年(40)

分类: LINUX

2010-06-22 10:19:07

1,访问共享资源的代码区称为临界区(critical sections)

2,解决竟态问题的途径:保证共享资源的互斥访问

3,解决方法:
  --中断屏蔽:使中断于进程之间的并发不再发生。
local_irq_disalbe() //屏蔽中断
...
critical sections //临界区
...
local_irq_enable() //开中断

local_irq_save(flags),除了屏蔽中断还能保存目前CPU的中断位信息, local_irq_restore(flags)恢复保存的中断位信息

local_bh_disable()禁止中断的底半部,local_bh_enable()

  --原子操作:执行过程中不会被别的代码路径所中断的操作
整型原子操作
//设置原子变量的值
void atomic_set(atomic_t *v, int i); //设置原子变量的值为1
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0

//获取原子变量的值
atomic_read(atomic_t *v);

//原子变量加/减
void atomic_add(atomic_t *v);
void atomic_sub(atomic_t *v);

//原子变量自增/自减
void atomic_inc(atomic_t *v);
void atomic_dec(atomic_t *v);

//操作并测试
int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(int i, atomic_t *v);
操作后测试是否为0,为0返回true,否则返回false

//操作并返回
int atomic_add_return(int i, atomic_t *v);
int atomic_sub_return(int i, atomic_t *v);
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);
操作后返回新值

位原子操作
//设置位,设置addr地址的第nr位为1
void set_bit(nr, void *addr);

//清除位,设置addr地址的第nr位为0
void clear_bit(nr, void *addr);

//改变位, 反位addr地址的第nr的值
void change_bit(nr, void *addr);


//测试位
int test_bit(nr, void *addr);

//测试并操作位
int test_and_set_bit(nr, void *addr);
int test_and_clear_bit(nr, void *addr);
int test_and_change_bit(nr, void *addr);

  --自旋锁(spin lock)
//定义自旋锁
spinlock_t lock;

//初始化自旋锁
spin_lock_init(&lock);

//获得自旋锁
spin_lock(lock); //自旋,直到该自旋锁的持有者释放该自旋锁
spin_trylock(lock); //尝试获得自旋锁lock,获取返回真,没有获得返回假

//释放自旋锁
spin_unlock(lock);

spin_lock_irq() = spin_lock() + local_irq_disable()
spin_unlock_irq() = spin_unlock + local_irq_enable()

spin_lock_saveirq() = spin_lock() + local_irq_save()
spin_lock_restoreirq() = spin_unlock() + locak_irq_restore()

spin_lock_bh() = spin_lock() + local_bh_disable()
spin_unlock_bh() = spin_lock() + local_bh_enable()

举例

spinlock_t lock;
spin_lock_init(&lock);

spin_lock(lock);
...
critical section //临界区

...
spin_unlock(lock);

 
读写自旋锁:一种比自旋锁颗粒更小的锁机制,保留了“自旋”的概念,写操作方面,只能最多有一个写进程,读操作方面,同时可以有多个读执行。但读操作与写操作不能同时进行
// 定义和初始化读写自旋锁
  /* 静态初始化 */
rwlock_t my_rwlock = RW_LOCK_UNLOCKED;
  /* 动态初始化 */
rwlock_t my_rwlock;
rwlock_init(&my_rwlock);

// 读锁定
void read_lock(rwlock_t *my_rwlock);
void read_lock_irqsave(rwlock_t *my_rwlock, unsinged long flags); //read_lock() + local_irq_save(flags)
void read_lock_irq(rwlock_t *my_rwlock); //read_lock() + lock_irq_disable()
void read_lock_bh(rwlock_t *my_rwlock); //read_lock() + lock_bh_disable()

// 读解锁
void read_unlock(rwlock_t *my_rwlock); 
void read_unlock_irqrestore(rwlock_t *my_rwlock, unsigned long flags); //read_unlock + local_irq_restore(flags)
void read_unlock_irq(rwlock_t *my_rwlock); //read_unlock() + local_irq_enable()
void read_unlock_bh(rwlock_t *my_rwlock); //read_unlock() + locak_bh_enable()

// 写锁定
void write_lock(rwlock_t *my_rwlock);
void write_lock_irqsave(rwlock_t *my_rwlock, unsigned long flags); //write_lock() + local_irq_save(flags)
void write_lock_irq(rwlock_t *my_rwlock); //write_lock() + local_irq_disable()
void write_lock_bh(rwlock_t *my_rwlock); //write_lock() + local_bh_disable()

// 写解锁
void write_unlock(rwlock_t *my_rwlock);
void write_unlock_irqrestore(rwlock_t *my_rwlock, unsigned long flags); //write_unlock() + local_irq_restore(flags)
void write_unlock_irq(rwlock_t *my_rwlock); //wirte_unlock() + local_irq_enable()
void write_unlock_bh(rwlock_t *my_rwlock); //write_unlock() + local_bh_enable()
 
顺序锁(seqlock):对读写锁的一种优化,读写操作能同时进行,但写操作与写操作间仍然是互斥的
1, 在LINUX内核中,写执行单元涉及及如下顺序锁操作
//获得顺序锁

void write_seqlock(seqlock_t *sl);
int write_tryseqlock(seqlock_t *sl);
write_seqlock_irqsave(seqlock_t *sl, flags);
write_seqlock_irq(seqlock_t *sl);
write_seqlock_bh(seqlock_t *sl);

其中:

write_seqlock_irqsave() = local_irq_save() + write_seqlock()
write_seqlock_irq() = local_irq_disable() + write_seqlock()
write_seqlock_bh() = local_irq_bh() + write_seqlock()


//释放顺序锁

void write_sequnlock(seqlock_t *sl);
write_sequnlock_irqrestore(seqlock_t *sl, flags);
write_sequnlock_irq(seqlock_t *sl);
write_sequnlock_bh(seqlock_t *sl);

其中:

write_sequnlock_irqrestore() = local_irq_irqrestore() + write_sequnlock()
write_sequnlock_irq() = local_irq_enable() + write_sequnlock()
write_sequnlock_bh() = local_bh_enable() + write_unlock()


2,读执行单元涉及如下顺序锁操作
//读开始

read_seqbegin(const seqlock_t *sl);
read_seqbegin_irqsave(lock, flags);
其中:
read_seqbegin_irqsave() = local_irq_save() + read_seqbegin()


//重读

int read_seqretry(cost seqlock_t *sl, unsigned iv);
read_seqretry_irgrestore(lock, iv, flags)
其中:
read_seqretry_irqrestore() = read_seqretry() + local_irq_restore()


读执行单元使用顺序锁的模式如下:

do{
    seqnum = read_seqbegin(&seqlock_a);
    //读操作模块

    ...
}while(read_seqretry(&seqlock_a, seqnum));



  --信号量

信号量的四种操作:
//定义信号量

struct semaphore sem;


//初始化信号量
/* 初始化信号量,并设置信号量的值为val */

void sema_init(struct semaphore *sem, int val);


/* 初始化一个用于互斥的信号量,且信号量的值为1 */

void init_MUTEX(struct semaphore *sem);


/* 初始化一个信号量,且值为0 */

void init_MUTEX_LOCKED(struct semaphore *sem);


两个宏定义并初始化信号量

DECLARE_MUTEX(name);
DECLARE_MUTEX_LOCKED(name);
前者定一个名叫name的信号量且初始值为1,后者为0


// 获得信号量

/* 获取信号量,它会导致睡眠,因此不能在中断上下文中使用 */

void dowm(struct semaphore *sem)


/* 不同与down(),进入睡眠状态的进程能被信号打断,信号也会导致该函数的返回,只是函数返回非0值 */

int down_interruptible(struct semaphore *sem);


/* 尝试获得信号量sem,如果能立即获得返回0,否则,返回非0。它不会导致调用者睡眠,可用于上下文 */

int down_trylock(struct semaphore *sem);

使用down_interruptible需要检查返回值

if (down_interruptible(&sem))
{
    return -ERESTARTSYS;
}


// 释放信号量
/* 释放信号量,唤醒等待着 */

void up(struct semaphore *sem);


DECLARE_MUTEX(mount_sem);//定义信号量

down(&mount_sem); //获得信号量
...
critical section //临界区
...
up(&mount_sem); //释放信号量


阅读(1325) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~