Linux 设备驱动--- 并发 之- 信号量 --- semaphore --- down_interruptible --- 按键信号量使用

时间:2022-07-12 15:17:05


信号量:

          Linux 内核的信号量概念和原理上与用户态的信号量是一样的

          但是它不能在内核之外使用,只能在内核中,它是一种睡眠锁.

          如果有一个任务想要获得 已经被占用 的信号量时,信号量会将这个进程放入一个等待队列 然后让其睡眠

         当持有信号量的进程将信号释放后,处于等待队列中的任务将被唤醒,并让其获得信号量.

          1,信号量在创建时需要设置一个初始值,表示允许有几个任务同时访问该信号量保护的资源.

                初始值为 1 就变成互斥锁 (  Mutex ) ,即同时只能有一个任务可以访问信号量保护的资源.

          2,当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加 1 实现.

                 如果释放后信号量的值为非正数,表明有任务等待当前信号量,因此要唤醒等待该信号量的任务.


定义信号量 struct   semaphore

          信号量的实现也是与体系结构相关的,定义在 < asm/semaphore.h > 中,

          struct   semaphore 类型用来表示信号量.

          eg: struct   semaphore   sem;


初始化信号量 sema_init   init_MUTEX   init_MUTEX_LOCKED 

          void  sema_init  ( struct  semaphore *sem , int  val )

          该函数用于初始化设置 信号量 的初值,它设置信号量 sem 的值 为 val .


          初始化一互斥锁 MUTEX:

          void  init_MUTEX ( struct  semaphore  *sem )

          该函数用于初始化一个互斥锁,即它把信号量 sem 的值设置为 1.

          void  init_MUTEX_LOCKED ( struct  semaphore *sem)

          该函数也用于初始化一个互斥锁,但是它把信号量 sem 的值设置为 0,即一开始就处在已锁状态.


初始化 定义一步完成 DECLARE_MUTEX  DECLARE_MUTEX_LOCKED  :

          定义与初始化的工作可由如下宏一步完成:

          DECLARE_MUTEX ( name )

          定义一个信号量 name,并初始化她的值为 1 .

          DECLARE_MUTEX_LOCKED ( name )

          定义一个信号量 name ,但把它的初始化设置为 0 ,即锁在创建时就处在已锁状态.


获取信号量  down  down_interruptible  down_trylock  

        1,  void   down ( struct  semaphore * sem )

          获得信号量 sem . 可能会导致进程睡眠,因此不能在中断上下文使用该函数.

          该函数将把 sem 的值减 1,如果信号量 sem 的值非负,就直接返回

          否则调用者将被挂起直到别的任务释放该信号量才能继续使用.

        2,  int  down_interruptible ( struct  semaphore * sem )

          获取信号量 sem . 如果信号量不可用,进程将被置为 TASK_INTERRUPTIBLE 类型的睡眠状态.

          该函数由返回值来区分是正常返回还是被信号中断返回,

          如果返回 0 ,表示获得信号量正常返回,

          如果被信号打断,返回 ——EINTR .

        3,  down_trylock ( struct  semaphore * sem )

          获取信号量 sem . 如果信号量不可获取,down_trylock  会立即返回 一个 非零值.  down_trylock  它永远不会休眠

          注:

                    down () 函数现已不建议继续使用,建议使用  down_killable ()或  down_interruptible ()


释放信号量  up  

          void  up ( struct  semaphore *sem )

          该函数释放信号量 sem ,即把 sem 的值加 1,如果 sem 的值为非负数,

          表明有任务等待该信号量,因此唤醒这些等待者.



实例 --- 按键信号量使用:


1,初始化,定义信号量:

在驱动程序开头初始化,定义信号量:

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

2,获取信号量:

在 open 函数中获取信号量,获取到就继续执行,否则休眠;

/* 获取信号量 */
down(&button_lock);


3,释放信号量:

程序退出,close 释放信息量:

up(&button_lock); /* 释放信号量 */
return 0;

4,执行测试应用程序:

两个应用程序同时去打开这驱动,

两个应用程序都放在后台执行;

首先,第一个的应用程序的 stat 为 S 睡眠状态;

第二个应用程序的 stat 为 D 状态,为僵死,不可中断的睡眠状态;

只有第一个应用程序退出的时候 ( kill 掉 )

这时第一个应用程序 释放了信号量 up(&button_lock); ,

才会去唤醒第二个应用程序,

第二个应用程序才能继续执行

第二个应用程序处于正常运行状态.