【内核】同步机制

一、概述

并发:多个执行单元同时或并行运行
竞争:多个执行单元同时并行的访问某个共享资源,导致竞争,竟态。
同步:多个执行单元协调动作,相互配合,串行的共同完成一个任务。
发生竟态时,可以使用以下方法对临界资源做同步处理:

  • 原子量(atomic)
    用于临界资源数量控制
  • 自旋锁(spin_lock)
    进程上下文和中断上下文都能使用,CPU 获取不到自旋锁,会忙等待.
    代码获取自旋锁后:
    1、不受别的CPU和本CPU的进程抢占打扰,但可以被中断和底半部抢占
    2、进行调度,抢占以及在等待队列、互斥锁、信号量上睡眠都是非法的
  • 互斥锁(mutex)
    互斥锁用来保证在任一时刻只能有一个线程访问或执行临界区,只能用于进程上下文
  • 信号量(semphore)
    信号量是用于保护临界区的一种常用方法,只能进程上下文获取信号量。
    信号量只能用于进程上下文,不能用于中断上下文,也不能持有自旋锁情况下使用信号量。

二、函数接口

1. 原子量

atomic_t v = ATOMIC_INIT(0);     //定义原子变量v并初始化为0
atomic_read(atomic_t *v);        //返回原子变量的值
void atomic_inc(atomic_t *v);    //原子变量增加1
void atomic_dec(atomic_t *v);    //原子变量减少1
int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。

2. 自旋锁

spin_lock_init();
spin_lock
spin_unlock
spin_lock_irq           禁止中断
spin_unlock_irq         恢复中断
spin_lock_irqsave
spin_unlock_irqrestore
spin_lock_bh      = spin_lock +  local_bh_disable  关底半部
spin_unlock_bh    =   spin_unlock + local_bh_enable   开底半部

3. 互斥锁

struct mutex my_mutex;
mutex_init(&my_mutex);
DEFINE_MUTEX(mutexname) //以上两句的合二为一
mutex_lock()
mutex_lock_interruptible()   ///可被中断打断
mutex_lock_killable()  ///可被信号打断
mutex_trylock()  //返回1,代码获取互斥锁成功
mutex_destroy
mutex_unlock

3. 信号量

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

DEFINE_SEMAPHORE(name)  //信号量资源值初始化为1 ,此时与互斥锁类似

void down(struct semaphore *sem); //获取信号量,资源值减1
void down_interruptible(struct semephore *sem)//获取信号量,资源值减1,睡眠后可被信号中断
void down_trylock(struct semaphore *sem);//不会导致调用者睡眠,可以在中断上下文使用,返回0 获取信号量成功
void down_timeout(struct semaphore *sem, long jiffies) // 超时,返回
int down_killable(struct semaphore *sem) //
void up(struct semaphore *sem);//释放信号量,资源值加1

三、代码示例

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/atomic.h>
#include <linux/spinlock.h>
#include <linux/semaphore.h>

#define hp_prt(fmt, arg...)  printk("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg);
spinlock_t hp_lock;
struct semaphore hp_sem;
DEFINE_MUTEX(hp_mutex);

void timer_func(struct timer_list * timelist)
{ 
    hp_prt("enter\n");
    /* 中断上下文与进程上下文使用同一个自旋锁时,应使用spin_lock_irq.进程上下文拿锁后被中断再拿锁可能导致死锁 */
    spin_lock(&hp_lock); 
    hp_prt("spin_lock get enter\n");
    spin_unlock(&hp_lock);
   
    mdelay(30000);// 中断中可以使用忙等延时,不能使用睡眠。
    hp_prt("up semaphore!\n");
    up(&hp_sem); // 释放信号量 code_case_concurrent_init执行完成
}

DEFINE_TIMER(hp_timer,timer_func);

static int code_case_concurrent_init(void)
{
    int r;
    static atomic_t canopen = ATOMIC_INIT(1);

    atomic_inc(&canopen);
    r = atomic_read(&canopen);
    hp_prt("atomic_read:%d\n", r);
    atomic_dec(&canopen);
    r = atomic_read(&canopen);
    hp_prt("atomic_read:%d\n", r);
    if(atomic_dec_and_test(&canopen)){
        hp_prt("atomic_dec_and_test == 0\n");
    }
    
    sema_init(&hp_sem, 1); //信号量资源初始化为1
    
    spin_lock_init(&hp_lock);
    spin_lock(&hp_lock);
    hp_prt("spin_lock get!\n");    
    hp_timer.expires = jiffies + 1 * HZ;  // 2s 后 进入时钟软中断
    add_timer(&hp_timer);  
   
    down(&hp_sem);// 非法操作,若获取不到资源,则会崩溃,此处继续执行
    // msleep(2000); 非法操作
    mdelay(2000);  // 时钟中断自旋,2s unlock,中断继续执行
    spin_unlock(&hp_lock);  //经在单核CPU上测试,timer在unlock后才执行。
    hp_prt("spin_unlock out!\n"); 

    down(&hp_sem);// 系统在此处阻塞, timer_func执行释放信号量
    hp_prt("get sem  OK!\n");

    hp_prt("mutex_lock start! \n");    
    mutex_lock(&hp_mutex); //只能在进程上下文使用
    msleep(2000);
    mutex_unlock(&hp_mutex);
    hp_prt("timer_func  mutex_lock out \n");
    return 0;
}
static void code_case_concurrent_exit(void)
{
     hp_prt("[%s,%d] enter!\n",__FUNCTION__,__LINE__); 
}

MODULE_AUTHOR("hpz");
MODULE_LICENSE("Dual BSD/GPL");
module_init(code_case_concurrent_init);
module_exit(code_case_concurrent_exit);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值