要建立乙個核心執行緒有許多種方法,我們這裡要學的是最簡單的一種。開啟include/linux/kthread.h,你就看到了它全部的api,一共三個函式。
structtask_struct kthread_run(int(*threadfn)(void*data),
void*data,const
charnamefmt,...);
intkthread_stop(structtask_struct *k);
intkthread_should_stop(void);
kthread_run()負責核心執行緒的建立,引數包括入口函式 threadfn,引數data,執行緒名稱namefmt。可以看到執行緒的名字可以是類似sprintf方式組成的字串。如果實際看到 kthread.h檔案,就會發現kthread_run實際是乙個巨集定義,它由kthread_create()和wake_up_process() 兩部分組成,這樣的好處是用kthread_run()建立的執行緒可以直接執行,使用方便。
kthread_stop()負責結束建立的執行緒,引數是建立時返回的task_struct指標。kthread設定標誌should_stop,並等 待執行緒主動結束,返回執行緒的返回值。執行緒可能在kthread_stop()呼叫前就結束。(經過實際驗證,如果執行緒在kthread_stop()呼叫 之前就結束,之後kthread_stop()再呼叫會發生可怕地事情—呼叫kthread_stop()的程序crash!!之所以如此,是由於 kthread實現上的弊端,之後會專門寫文章講到)
kthread_should_stop()返回should_stop標誌。它用於建立的執行緒檢查結束標誌,並決定是否退出。執行緒完全可以在完成自己的工作後主動結束,不需等待should_stop標誌。
下面就來嘗試一下執行不息的核心執行緒吧。
1、把上節建立的hello子目錄,複製為新的kthread子目錄。
2、修改hello.c,使其內容如下。
#include
#include
#include
module_license("dual bsd/gpl");
static
structtask_struct *tsk;
static
intthread_function(void*data)
while(!kthread_should_stop() && time_count<=30);
returntime_count;
}static
inthello_init(void)
else
return0;
}static
voidhello_exit(void)
} module_init(hello_init);
module_exit(hello_exit);
為了不讓建立的核心執行緒一直執行浪費cpu,**中採用週期性延遲的方式,每次迴圈 用msleep(1000)延遲1s。為了防止執行緒一直執行下去,**中使用了兩個結束條件:乙個是模組要求執行緒結束,乙個是列印滿一定次數,後者是為了 防止printk輸出資訊太多。最後在hello_exit中結束執行緒,並列印執行緒執行的時間。
這裡要注意的是kthread_run的返回值tsk。不能用tsk是否為null進行檢查,而要用is_err()巨集定義檢查,這是因為返回的是錯誤碼,大致從0xfffff000~0xffffffff。
3、編譯執行模組,步驟參照前例。在執行過程中使用ps -e命令,可以看到有名字位mythread1的核心執行緒在執行。
經過本節,我們學習了核心執行緒的建立使用方法,現在要建立一大堆的執行緒在核心中已經易如反掌。你會逐漸相信,我們模組的拓展空間是無限的。
附註:我們的重點在模組程式設計,不斷學習核心api的使用。但如果能知其然,而知其所以然就更好了。所以有了文章後的附註部分。在附註部分,我們會盡量解釋核心 api的實現原理,對相關linux核心**做簡單的分析,以幫助大家學習理解相關的**。分析的**包含在linux-2.6.32中,但這些**在相 近版本中都變化不大。作者水平有限,請大家見諒。
kthread的實現在kernel/kthread.c中,標頭檔案是include/linux/kthread.h。核心中一直執行乙個執行緒 kthreadd,它執行kthread.c中的kthreadd函式。在kthreadd()中,不斷檢查乙個kthread_create_list 鍊錶。kthread_create_list中的每個節點都是乙個建立核心執行緒的請求,kthreadd()發現鍊錶不為空,就將其第乙個節點退出鏈 表,並呼叫create_kthread()建立相應的執行緒。create_kthread()則進一步呼叫更深層的kernel_thread()建立 執行緒,入口函式設在kthread()中。
外界呼叫kthread_run建立執行執行緒。kthread_run是個巨集定義,首先呼叫kthread_create()建立執行緒,如果建立成功,再 呼叫wake_up_process()喚醒新建立的執行緒。kthread_create()根據引數向kthread_create_list中傳送一 個請求,並喚醒kthreadd,之後會呼叫wait_for_completion(&create.done)等待執行緒建立完成。新建立的線 程開始執行後,入口在kthread(),kthread()呼叫complete(&create->done)喚醒阻塞的模組程序,並 使用schedule()排程出去。kthread_create()被喚醒後,設定新執行緒的名稱,並返回到kthread_run中。 kthread_run呼叫wake_up_process()重新喚醒新建立執行緒,此時新執行緒才開始執行kthread_run引數中的入口函式。
from:
執行不息的核心執行緒kthread
上節中,我們成功地編譯執行了乙個linux模組。可惜的是,它只有兩個函式,hello init在模組載入時呼叫,hello exit 在模組解除安裝時呼叫。這樣下去,模組縱使有天大的本事,也只能壓縮在這兩個函式中。為了避免這種悲劇發生,本節就來學習一種讓模組在載入後能一直執行下去的方法 核心執行緒。...
執行不息的核心執行緒kthread
要建立乙個核心執行緒有許多種方法,我們這裡要學的是最簡單的一種。開啟include linux kthread.h,你就看到了它全部的api,一共三個函式。structtask struct kthread run int threadfn void data void data,const cha...
核心執行緒是怎麼執行
pid t kernel thread int fn void void arg,unsigned long flags 通過這個函式可以建立核心執行緒,執行乙個指定函式fn。但是這個fn是怎麼執行的了?pid t kernel thread int fn void void arg,unsigne...