嵌入式驅動學習第一周——linux的休眠與喚醒

前言

?? 本文介紹進程的休眠與喚醒。

?? 嵌入式驅動學習專欄將詳細記錄博主學習驅動的詳細過程,未來預計四個月將高強度更新本專欄,喜歡的可以關注本博主并訂閱本專欄,一起討論一起學習。現在關注就是老粉啦!

行文目錄

  • 前言
  • 1. 阻塞和非阻塞
  • 2. 進程的幾種狀態
  • 3. 等待隊列
    • 3.1 等待隊列頭
    • 3.2 等待隊列項
  • 參考資料

1. 阻塞和非阻塞

?? 當應用程序對設備驅動進行操作時,如果不能獲取到設備資源,那么阻塞IO就會將應用程序掛起,直到設備資源可以獲取為止。其模式如下所示:

在這里插入圖片描述

?? 應用程序調用read函數從設備中讀取數據,當設備不可用或數據未準備好的時候進入到休眠態,等設備可用就會從休眠態喚醒,然后從設備中讀取數據返回到應用程序。

?? 阻塞訪問最大的好處就是當設備文件不可操作時進程進入休眠態,可以把CPU資源讓出來。

?? 應用程序用阻塞IO訪問的代碼如下。默認讀取方式就是阻塞式訪問。

int fd;
int data = 0;fd = open("dev/xxx_dev", O_RDWR);			// 阻塞方式打開
ret = read(fd, &data, sizeof(data));		// 讀取數據

?? 非阻塞式IO中,應用程序對應的線程不會掛起,要么一直輪詢等待,直到設備資源可用,要么直接放棄,其模式如下:

在這里插入圖片描述

?? 應用程序調用read函數從設備中獲取數據,當設備不可用或數據未準備好時會立即向內核返回一個錯誤碼,表示數據讀取失敗,應用程序會再次重新讀取數據,這樣循環往復,直到數據讀取成功。

?? 應用程序用阻塞IO訪問的代碼如下,主要在open函數的第二個參數上有變化:

int fd;
int data = 0;fd = open("dev/xxx_dev", O_RDWR | O_NONBLOCK);			// 阻塞方式打開
ret = read(fd, &data, sizeof(data));		// 讀取數據

2. 進程的幾種狀態

TASK_RUNNING: 正在運行或處于就緒狀態:就緒狀態是指進程申請到了CPU以外的其他所有資源,提醒:一般的操作系統教科書將正在CPU上執 行的進程定義為RUNNING狀態、而將可執行但是尚未被調度執行的進程定義為READY狀態,這兩種狀態在Linux下統一為 TASK_RUNNING狀態.
??
TASK_INTERRUPTIBLE: 處于等待隊伍中,等待資源有效時喚醒(比如等待鍵盤輸入、socket連接、信號等等),但可以被中斷喚醒.一般情況下,進程列表中的絕大多數進程都處于 TASK_INTERRUPTIBLE狀態.畢竟皇帝只有一個(單個CPU時),后宮佳麗幾千;如果不是絕大多數進程都在睡眠,CPU又怎么響應得過來.
??
TASK_UNINTERRUPTIBLE:處于等待隊伍中,等待資源有效時喚醒(比如等待鍵盤輸入、socket連接、信號等等),但不可以被中斷喚醒.
??
TASK_ZOMBIE:僵死狀態,進程資源用戶空間被釋放,但內核中的進程PCB并沒有釋放,等待父進程回收.
??
TASK_STOPPED:進程被外部程序暫停(如收到SIGSTOP信號,進程會進入到TASK_STOPPED狀態),當再次允許時繼續執行(進程收到SIGCONT信號,進入TASK_RUNNING狀態),因此處于這一狀態的進程可以被喚醒.

3. 等待隊列

?? 阻塞訪問中,如果設備不可操作的時候,進程進入休眠態,但當設備文件可以操作時就必須喚醒進程,一般在終端中完成喚醒工作。Linux內核提供等待隊列來實現阻塞進程的喚醒工作。

3.1 等待隊列頭

?? 如果要使用等待隊列,必須先新建并初始化一個等待隊列頭,等待隊列頭使用結構體wait_queue_head_t

struct __wait_queue_head {spinlock_t lock;struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

?? 定義好等待隊列頭后就使用函數init_waitqueue_head進行初始化。

/** @description: 初始化等待隊列頭* @param-q    : 要初始化的等待隊列頭* @return     : 無*/
void init_waitqueue_head(wait_queue_head_t *q)

3.2 等待隊列項

?? 等待隊列頭是一個等待隊列的頭部,每個訪問設備的進程為一個隊列項,當設備不可用時將這些進程對應的等待隊列項添加到等待隊列中,用結構體wait_queue_t表示等待隊列項

struct __wait_queue {unsigned int flags;void *private;wait_queue_func_t func;struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;

?? DECLARE_WAITQUEUE 定義并初始化一個等待隊列項

// 定義并初始化一個等待隊列,name是等待隊列項的名字,tsk是該等待隊列項屬于哪個任務(進程),一般設置為current
DECLARE_WAITQUEUE(name, tsk)

?? 以下是添加等待隊列項的函數:

/** @description: 添加隊列項* @param-q    : 等待隊列項要加入的等待對獵頭* @param-wait : 要加入的等待隊列項* @return     : 無*/
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

?? 以下是刪除等待隊列項的函數:

/** @description: 刪除隊列項* @param-q    : 要刪除等待隊列項的等待對獵頭* @param-wait : 要刪除的等待隊列項* @return     : 無*/
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

?? 喚醒休眠態進程有兩個函數wake_up()wake_up_interruptible()

wake_up 可以喚醒處于TASK_INTERRUPTIBLETASK_UNINTERRUPTIBLE狀態的進程
wake_up_interruptible只可以喚醒處于TASK_INTERRUPTIBLE的進程

/** @description: 環境休眠態的進程* @param-q    : 要喚醒的等待隊列頭,其中的所有線程都會喚醒* @return     : 無*/
void wake_up(wait_queue_head_t *q)
void wake_up_interruptible(wait_queue_head_t *q)

?? 除了主動喚醒,也可以設置等待隊列等待某個事件來喚醒等待隊列的線程。

/** @description    : 當condition為真時,喚醒以wq為等待對獵頭的等待隊列,condition為假時,會一直阻塞。* 					此函數會將進程設置為TASK_UNINTERRUPTIBLE 狀態* @param-wq       : 要喚醒的等待隊列頭,其中的所有線程都會喚醒* @param-condition: 喚醒條件* @return         : 無*/
wait_event(wq, condition)
/** @description    : 功能和 wait_event 類似,但是此函數可以添加超時時間,以 jiffies 為單位* @param-wq       : 要喚醒的等待隊列頭,其中的所有線程都會喚醒* @param-condition: 喚醒條件* @param-timeout  : 超時時間* @return         : 0,表示超時時間到,而且 condition為假。1,表示 condition 為真,也就是條件滿足了*/
wait_event_timeout(wq, condition, timeout)
/** @description    : 與 wait_event 函數類似,但是此函數將進程設置為 TASK_INTERRUPTIBLE,就是可以被信號打斷*/
wait_event_interruptible(wq, condition)
/** @description    : 與 wait_event_timeout 函數類似,但是此函數將進程設置為 TASK_INTERRUPTIBLE,就是可以被信號打斷*/
wait_event_interruptible_timeout(wq, condition, timeout)

總結:使用等待隊列實現阻塞訪問重點注意兩點:

①、將任務或者進程加入到等待隊列頭
②、在合適的點喚醒等待隊列,一般都是中斷處理函數里面。

參考資料

[1] 【正點原子】I.MX6U嵌入式Linux驅區動開發指南 第五十二章

[2] linux內核任務調度-- wait_event

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/713938.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/713938.shtml
英文地址,請注明出處:http://en.pswp.cn/news/713938.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第二節 數學知識補充

一、線性代數 向量的 L 2 L_2 L2?范數(Euclidean范數/Frobenius范數)&矩陣的元素形式范數 向量的 L 2 L_2 L2?范數: ∣ ∣ x ∣ ∣ 2 ( ∣ x 1 ∣ 2 ? ∣ x m ∣ 2 ) 1 2 ||x||_2(|x_1|^2\cdots|x_m|^2)^{\frac12} ∣∣x∣∣2?(∣…

Verilog參數、Verilog參數和屬性沖突、整數處理

Verilog參數 Verilog參數執行以下操作: ?允許您創建易于重用和擴展的參數化代碼。 ?使代碼更可讀、更緊湊、更易于維護。 ?將此類功能描述為: ○ 總線尺寸 ○ 建模設計單元中某些重復元素的數量 ?是常數。對于參數化模塊的每個實例化&#xf…

電腦桌面便簽哪個好,好用的電腦桌面便簽推薦

在如今信息爆炸的時代,人們的工作和生活節奏越來越快,記事和備忘變得尤為重要。而電腦桌面便簽作為一種方便快捷的記錄工具,備受廣大用戶青睞。那么,電腦桌面便簽哪個好,哪個更加出色呢? 作為一名人事專員…

CryoEM - 使用 cryoSPARC 基于單顆粒圖像從頭重構蛋白質三維結構

歡迎關注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/136384544 基于冷凍電鏡單顆粒圖像重構蛋白質三維結構,利用冷凍電鏡技術測定生物大分子結構的方法。原理是從冷凍電鏡獲得大量同一種蛋白質分子的二維投影圖…

【數據結構】實現隊列

大家好,我是蘇貝,本篇博客帶大家了解隊列,如果你覺得我寫的還不錯的話,可以給我一個贊👍嗎,感謝?? 目錄 一. 隊列的概念及結構二. 隊列的實現隊列的結構體初始化銷毀隊尾插入隊頭刪除顯示第一個節點的值…

【Java程序員面試專欄 算法思維】六 高頻面試算法題:動態規劃

一輪的算法訓練完成后,對相關的題目有了一個初步理解了,接下來進行專題訓練,以下這些題目就是匯總的高頻題目,本篇主要聊聊回溯算法,主要就是排列組合問題,所以放到一篇Blog中集中練習 題目關鍵字解題思路時間空間零錢兌換動態規劃+雙重循環dp[i]表示兌換金額為i元的最少…

從0開始學習NEON(0)

1、前言 ? 最近在學習NEON指令集,主要學習"單指令流,多數據流"的編程方式,在這之前主要是針對cuda編程進行學習。最近的一部分工作轉移到了arm主板上,接觸到了 ncnn這個開源項目,不得不佩服nihui的強大。在…

C# 線性插值

線性插值是一種常用的插值算法,適用于許多實際場景。 傳感器數據處理:在傳感器數據處理中,可能會出現數據點不連續或不均勻的情況。使用線性插值可以根據已知的數據點來估算在兩個數據點之間的數值,從而填補數據中的缺失或不連續之…

iOS消息轉發流程

當向Objc對象發送消息時,如果找到對象對應的方法,就會進入消息轉發流程,給開發者提供一些最后的機會處理消息無法發送問題,以免出現程序崩潰。 1. 回調對象的resolveInstanceMethod方法,在這個方法中,允許開…

阿里云定價_ECS產品價格_云服務器收費標準 - 阿里云官方活動

2024年最新阿里云服務器租用費用優惠價格表,輕量2核2G3M帶寬輕量服務器一年61元,折合5元1個月,新老用戶同享99元一年服務器,2核4G5M服務器ECS優惠價199元一年,2核4G4M輕量服務器165元一年,2核4G服務器30元3…

logo設計軟件及網站匯總

文章目錄 一、智能設計logo的網站二、常用的logo設計軟件 一、智能設計logo的網站 Canva:Canva是一個在線設計平臺,提供了豐富的模板和設計工具,可以幫助用戶輕松設計出專業水平的logo。 DesignEvo:DesignEvo是一個專業的在線log…

基于 LLaMA 和 LangChain 實踐本地 AI 知識庫

有時候,我難免不由地感慨,真實的人類世界,本就是一個巨大的娛樂圈,即使是在英雄輩出的 IT 行業。數日前,Google 正式對外發布了 Gemini 1.5 Pro,一個建立在 Transformer 和 MoE 架構上的多模態模型。可惜,這個被 Google 寄予厚望的產品并未激起多少水花,因為就在同一天…

動作生成學習筆記

目錄 ReMoDiffus 檢索和擴散 文字生運動 action生運動 ReMoDiffus 檢索和擴散 ICCV 2023 | 重塑人體動作生成,融合擴散模型與檢索策略的新范式ReMoDiffuse來了,根據文本生成動作 有例子和模型&

CSS 顯示隱藏動畫(動畫失效問題)

就像這個動畫一樣的效果&#xff0c;div 先是隱藏的&#xff0c;點擊按鈕后顯示并且有動畫效果&#xff0c;隱藏的時候同樣。 <button class"btn" id"btn">點擊</button><div class"box" id"box"></div><s…

一些常用到的git命令

git stash -a //緩存所有文件 git checkout -b dev origin/dev //切換到dev分支上,接著跟遠程的origin地址上的dev分支關聯起來 //推送本地分支到遠程倉庫 git push origin localbranchname:remotebrancname git revert onefile //https://www.freecodecamp.org/news/git-re…

S2---FPGA-A7板級原理圖硬件實戰

視頻鏈接 FPGA-A7板級系統硬件實戰01_嗶哩嗶哩_bilibili FPGA-A7板級原理圖硬件實戰 基于XC7A100TFGG484的FPGA硬件設計流程圖 A7核心板&#xff0c;是基于XILINX公司的ARTIX-7系列100T的XC7A100T,2FGG484I這款芯片開發的高性能核心板&#xff0c;具有高速&#xff0c;高帶寬&a…

HashMap在多線程下形成環的死鎖詳解

1. HashMap的工作原理 HashMap是Java中基于哈希表的Map接口的非同步實現。它存儲鍵值對&#xff0c;并允許使用null鍵和null值。HashMap通過使用鍵對象的hashCode()方法來決定鍵值對的存儲位置。 2. 多線程環境下的問題 在多線程環境下&#xff0c;如果多個線程同時對HashMap進…

Android 簽名機制

V1是內部文件單個簽 但是增加apk文件目錄下面隨意增加文件并不會有影響,它只關心meta-info文件 mf匯總清單的各個文件sha256 V2 整個APK文件,按文件進行hash 那么便不能隨便在這里面增加文件了,增加了簽名分塊&#xff08;不然簽名信息存哪里&#xff09;這里涉及一個文件概念 …

如何修煉成“神醫”——《OceanBase診斷系列》之一

本系列是基于OcenaBase 開發工程師在工作中的一些診斷經驗&#xff0c;也歡迎大家分享相關經驗。 1. 關于神醫的故事 扁鵲&#xff0c;中國古代第一個被正史記載的醫生&#xff0c;他的成才之路非常傳奇。年輕時&#xff0c;扁鵲是一家客棧的主管。有一位名叫長桑君的客人來到…

性能優化篇(二) 靜態合批步驟與所有注意事項\游戲運行時使用代碼啟動靜態合批

靜態合批步驟: 1.開啟Project Settings —>Player–>Other Setting里勾選Static Batching選項(一般情況下unity都是默認勾選狀態) 2.勾選需要合批的靜態物體上的Batching Static項,勾選后此物體下的所有子物體都默認參與靜態合批(勾選后物體不能進行移動/旋轉/縮放操作,…