linux字符设备驱动-同步互斥阻塞笔记

    xiaoxiao2021-03-25  119

    一、开发环境

    1、内核:Linux 2.6.22.6;

    2、JZ2440

    3、ubuntu 9.10

    二、互斥

    为了实现同一时绝对的只能有一个进程使用某个设备需要互斥机制,linux互斥机制有多种,如原子变量、互斥锁、信号量、自旋锁、读写锁等等。

    1、原子操作。指执行的过程中不会被别的代码路径所中断的操作。实现原子操作过程:

     1.1 其常使用的函数有:

    static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1

    atomic_dec_and_test(atomic_t *v))//自减操作,并检测是否为0,为0返回ture,为1返回false。

    atomic_read(atomic_t *v);//读取

    atomic_dec(atomic_t *v);//自减1

    atomic_inc(atomic_t *v);//自增1

     1.2 使用过程

     (1)设置原子变量。用来标记设备是否被占用。如定义原子变量canopen:

       static atomic_t canopen = ATOMIC_INIT(1);     //定义原子变量并初始化为1

     (2)在打开设备之前先测试设备是否可用。假设我们用1表示可用,检测函数如下。设备可用时,原子变量减1后为0,检测函数返回ture,非ture为false,则不执行if语句,此时原子变量也变为0,表示设备不可用。下面就可也写使用设备的函数了。

    if (!atomic_dec_and_test(&canopen))   //检测,设备不可用执行if语句 { atomic_inc(&canopen);    //将原子变量变回原来的值 return -EBUSY; }

    (3)在关闭设备的函数里最后把设备标记为未被占用。即使用atomic_inc(atomic_t *v),让原子变量为1,表示设备可用。

    使用原子变量,在原子变量加减的时候,不能其他操作打断,因而保证了绝对互斥,同一时间设备只能被一个进程使用。

    2、信号量

    信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。

    只有获取到信号量的进程才能打开设备,获取不到信号量的进程返回或休眠。

     2.1 使用函数

    定义信号量sem

    struct semaphore sem; 初始化信号量 void sema_init (struct semaphore *sem, int val); void init_MUTEX(struct semaphore *sem); //初始化为0 

    可用使用DECLARE_MUTEX,实现信号量的定义并初始化,如:DECLARE_MUTEX(name);  //定义一个信号量name,并初始化它的值为1。 

    注意init_MUTEX(),DECLARE_MUTEX 在linux2.6.38以后已被移除。其中DECLARE_MUTEX(name)被DEFINE_SEMAPHORE替代,为避免与DEFINE_MUTEX 互斥锁相近引起开发者误解。

    获得信号量 void down(struct semaphore * sem); int down_interruptible(struct semaphore * sem);   //获取不到休眠,可被中断 int down_trylock(struct semaphore * sem);      //获取不到立即返回 释放信号量 void up(struct semaphore * sem);

    2.2 使用过程

    (1)定义一个信号量。如,定义一个信号量button_lock:

    static DECLARE_MUTEX(button_lock);     //定义互斥锁

    (2)打开设备时先获得信号量。如,

    down(&button_lock);

    也可用其他函数。第一个进程执行到down函数时可以申请到信号量button_lock,第二个进程如果再申请则申请不到,进入休眠状态,直到信号量被释放,第二个进程就可以进行

    (3)关闭设备最后释放信号量。如,

      up(&button_lock);

    3、阻塞、非阻塞的实现

    3.1 阻塞操作,是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。   非阻塞操作,进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。 

    3.2 通过判断函数带入的参数file的file->f_flags来判断是否为阻塞,以做相应的操作。

             if (file->f_flags & O_NONBLOCK)     {   //非阻塞,实现立即返回     }    else    { //阻塞,实现休眠

       }

    实现后,应用程序调用实现后的函数时,可以选择阻塞或非阻塞方式,阻塞时陷入休眠,非阻塞时立即返回信息。一般默认是阻塞,应用程序设置非阻塞方式打开使用O_NONBLOCK,如下

        fd = open("...", O_RDWR | O_NONBLOCK);

    转载请注明原文地址: https://ju.6miu.com/read-5840.html

    最新回复(0)