日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

字符设备驱动程序之按键——同步互斥阻塞

發(fā)布時間:2024/9/3 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字符设备驱动程序之按键——同步互斥阻塞 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
我們知道在之前的應用程序中,如果我們同時運行兩次應用程序的話,則兩次都可以同時打開設備,這就是說我們的按鍵資源同時被兩個進程使用。顯然這不是我們想要的,那么下面我們就要引入互斥的概念。 關于互斥其實其實現(xiàn)很簡單,就是采用一些標志,當文件被一個進程打開后,就會設置該標志,使其他進程無法打開設備文件。下面,我們就完全靠自己去實現(xiàn)一個互斥,代碼修改如下:
首先定義一個全局變量: static int canread=1; 然后在open函數(shù)開始處加入如下代碼: ? if(--canread!=0) ? ? ? ? { ? ? ? ? ?? ? ? ? ? ? ? canread++; ? ? ? ? ? ? return -EBUSY; ? ? ? ? } 在close函數(shù)里面加入如下代碼: anread++; 我們可以先分析一下,當進程A打開設備文件時,因為初始值canread=1,canread減1后正好等于0,不會出錯返回,成功打開了。此時當進程B再來打開該設備文件時,因canread=0,canread減1不為0,所以會出錯出錯返回,且canread加1,canread=0。當進程A關閉后,canread加1,canread=1;這時如果B進程運行,會成功打開設備文件??瓷先ニ坪跬昝赖脤崿F(xiàn)了互斥,其實這其中是有問題的。因為其實對于: ?--canread! 這行代碼來說,它分為3的步驟,包括:讀取canread值,修改canread值,寫回canread的值。 但是不要忘記了,我們的linux系統(tǒng)是一個多任務的系統(tǒng),假如當A讀取了canread的值為1時,還沒來得及減1,就已經切換到了進程B,進程B讀出的canread的值也是1,這樣的話,B就成功打開了設備文件。如果這時再切換回了A,因為之前A已經讀出了canread為1,這時會將canread當作1來進行后續(xù)處理,也可以打開文件。這可不是我們想要的,那么有沒有其他辦法呢?答案是肯定的,下面來介紹兩種方法:
方法一:原子操作 定義:原子操作指的是在執(zhí)行過程中不會被別的代碼路徑所中斷的操作。 下面是幾個常用原子操作函數(shù): 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。 修改代碼:
首先定義全局原子變量: static atomic_t canread= ATOMIC_INIT(1); 然后在open函數(shù)開始處加入如下代碼: ?if(!atomic_dec_and_test(&canread)) ? ? ? ? { ? ? ? ? ?? ? ? ? ? ? ? atomic_inc(&canread); ? ? ? ? ? ? return -EBUSY; ? ? ? ? }
在close函數(shù)里面加入如下代碼: atomic_inc(&canread);
方法二:信號量 定義:信號量(semaphore)是用于保護臨界區(qū)的一種常用方法,只有得到信號量的進程才能執(zhí)行臨界區(qū)代碼。當獲取不到信號量時,進程進入休眠等待狀態(tài)。 下面是幾個常用的信號量相關的函數(shù):
2. 信號量 信號量(semaphore)是用于保護臨界區(qū)的一種常用方法,只有得到信號量的進程才能執(zhí)行臨界區(qū)代碼。 當獲取不到信號量時,進程進入休眠等待狀態(tài)。 定義信號量 struct semaphore sem; 初始化信號量 void sema_init (struct semaphore *sem, int val); void init_MUTEX(struct semaphore *sem);//初始化為0 static DECLARE_MUTEX(button_lock);?? ? //定義互斥鎖 獲得信號量 void down(struct semaphore * sem); int down_interruptible(struct semaphore * sem);? int down_trylock(struct semaphore * sem); 釋放信號量 void up(struct semaphore * sem); 修改代碼: 首先定義全局互斥鎖: static DECLARE_MUTEX(button_lock); 在open函數(shù)中獲得信號量: down(&button_lock); 在close函數(shù)中釋放信號量:
up(&button_lock); 我們測試時第一次運行應用程序,發(fā)現(xiàn)其狀態(tài)時S,第二次運行,其狀態(tài)時D,S表示睡眠狀態(tài),是因為沒有按鍵按下而產生睡眠,而D表示一種僵死狀態(tài),或者也可以說是一種睡眠狀態(tài),不過它是因為沒有獲取信號量而進入僵死。那么第二個進程什么時候才能從僵死狀 態(tài)喚醒呢?那就要等到第一個進程釋放信號量。我們將第一個進程殺死,發(fā)現(xiàn)第二個進程的狀態(tài)變成了S,從而驗證了我們的說法。
下面我們再來談一下阻塞和非阻塞的問題: 阻塞操作:是指在執(zhí)行設備操作時若不能獲得資源則掛起進程,直到滿足可操作的條件后再進行操作。被掛起的進程進入休眠狀態(tài),被從調度器的運行隊列移走,直到等待的條件被滿足。 非阻塞操作:進程在不能進行設備操作時并不掛起,它或者放棄,或者不停地查詢,直至可以進行操作為止。 我們在驅動程序中修改代碼: 在open函數(shù)中加入如下代碼: if (file->f_flags & O_NONBLOCK) { if (down_trylock(&button_lock)) return -EBUSY; } else { down(&button_lock); } 我們在read函數(shù)中加入如下代碼: if (filp->f_flags & O_NONBLOCK) { if (!ev_press) ?//如果沒有按鍵按下返回 return -EAGAIN; } else { wait_event_interruptible(button_waitq, ev_press);//這一句要將本來的注釋掉 } 將ev_press相關的定義添加上 添加定義:static DECLARE_WAIT_QUEUE_HEAD(button_waitq); 在中斷中補上這一句:wake_up_interruptible(&button_waitq);
測試程序如下: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <poll.h> #include <signal.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h>
int main(int argc, char **argv) { ? ? ? ? int fd; ? ?? unsigned char key_val; ? ? ? fd = open("/dev/keys", O_RDWR); if (fd < 0) { printf("can't open!\n"); }
while (1) { ?? ?read(fd, &key_val, 1); ?? ?printf("key_val: 0x%x\n", key_val); } return 0; } 默認情況下是阻塞方式打開的,運行測試程序,當我們沒有按下按鍵時會休眠,但不會返回。 我們將: fd = open("/dev/keys", O_RDWR);改為 fd = open("/dev/keys", O_RDWR |?O_NONBLOCK); 會變成非阻塞方式打開,這時沒有按鍵按下會返回。為方便測試,我們在循環(huán)里加入:sleep(5);

總結

以上是生活随笔為你收集整理的字符设备驱动程序之按键——同步互斥阻塞的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。