実行中のカーネルスレッドkthread

5487 ワード

カーネルスレッドを作成するには多くの方法がありますが、ここでは最も簡単な方法を学びます.include/linux/kthreadを開きます.h、あなたはそのすべてのAPIを見て、全部で3つの関数です.
struct task_struct kthread_run(int (*threadfn)(void *data), void *data,constchar namefmt[],...); 
int kthread_stop(struct task_struct *k); 
int kthread_should_stop(void); 

      kthread_run()はカーネルスレッドの作成を担当し、パラメータにはエントリ関数threadfn、パラメータdata、スレッド名namefmtが含まれます.スレッドの名前はsprintfのような文字列であることがわかります.実際に見たらhファイル、kthread_が見つかりますrunは実際にはkthread_によって定義されていますcreate()とwake_up_プロセス()の2つの部分からなり、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 <linux/init.h>  
#include <linux/module.h>  
#include <linux/kthread.h>
#include <linux/delay.h>


static struct task_struct *tsk=NULL; 
     
static int thread_function(void *data) 
{ 
        int time_count = 0; 
        do 
    { 
           printk(KERN_INFO "thread_function: %d times", ++time_count); 
           msleep(1000); 
        }while(!kthread_should_stop() && time_count<=30); 
        tsk=NULL;
        return time_count; 
} 
     
static int hello_init(void) 
{ 
        printk(KERN_INFO "Hello, world!
");               tsk = kthread_run(thread_function, NULL, "mythread%d", 1);         if (IS_ERR(tsk)) {             printk(KERN_INFO "create kthread failed!
");         }         else {             printk(KERN_INFO "create ktrhead ok!
");         }         return 0; }       static void hello_exit(void) {            int ret;         printk(KERN_INFO "Hello, exit!
");         if (!IS_ERR(tsk))     {         if(tsk)         {                 ret=kthread_stop(tsk);                 printk(KERN_INFO "thread function has run %ds
", ret);         }        } }       module_init(hello_init); module_exit(hello_exit);   MODULE_LICENSE("Dual BSD/GPL");

作成したカーネルスレッドがCPUを無駄にしないように,コードでは周期的に遅延する方式を採用し,サイクルごとにmsleep(1000)で1 s遅延する.スレッドが常に実行されることを防止するために、コードには2つの終了条件が使用されています.1つはモジュールがスレッドの終了を要求し、1つは印刷が一定回数いっぱいで、後者はprintk出力情報が多すぎることを防止するためです.最後にhello_exitでスレッドを終了し、スレッドの実行時間を印刷します.
ここで注意したいのはkthread_runの戻り値tsk.tskがNULLであるかどうかはチェックできませんが、IS_を使用します.ERR()マクロ定義チェックは、エラーコードが返され、ほぼ0 xfffff 000~0 xffffffffから返されるためである.
3、実行モジュールをコンパイルし、手順は前例を参照する.実行中にps-eコマンドを使用すると、有名なワードビットmythread 1のカーネルスレッドが実行されていることがわかります.
このセクションでは、カーネルスレッドの作成方法について説明します.カーネル内でスレッドを作成するのは簡単です.私たちのモジュールの拡張空間は無限だと信じています.
注記:
モジュールプログラミングに重点を置き、カーネルAPIの使用を絶えず学習しています.しかし、それを知ることができれば、それを知ることができればもっといい.だから文章の後の注釈部分があります.注記部分では、カーネルAPIの実現原理をできるだけ説明し、関連linuxカーネルコードを簡単に分析し、関連コードの理解を学ぶのに役立ちます.分析されたコードはlinux-2.6.32に含まれていますが、これらのコードは近いバージョンではあまり変わりません.作者のレベルは限られているので,ご了承ください.
kthreadの実装はkernel/kthread.cでは、ヘッダファイルはinclude/linux/kthread.h.カーネルでは、kthreaddを実行するスレッドkthreaddが実行されます.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_プロセス()は、新しく作成されたスレッドを起動します.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_プロセス()新規作成スレッドが再起動され、kthread_の実行が開始されます.runパラメータのエントリ関数.
外部呼び出しkthread_stop()スレッドを削除します.kthread_stopまず終了フラグshould_を設定stop、wake_を呼び出しますfor_completion(&kthread->exited)では、これは実は新しいスレッドtask_struct上のvfork_done、スレッド終了でdo_が呼び出されますexit()の場合に設定します.
スレッドは、通常、プロセス内のコードの異なる実行ルートとして定義されます.実装方法から、スレッドには2つのタイプがあります.「ユーザー・レベル・スレッド」と「カーネル・レベル・スレッド」です.
ユーザー・スレッドとは、カーネル・サポートを必要とせずにユーザー・プログラムで実装されるスレッドを指し、オペレーティング・システムのコアに依存せず、アプリケーション・プロセスはスレッド・ライブラリを使用してスレッドの作成、同期、スケジューリング、管理の関数を提供し、ユーザー・スレッドを制御します.このスレッドはDOSのようなオペレーティングシステムでも実現できるが、スレッドのスケジューリングにはWindows 3に似たユーザプログラムが必要である.xのコラボレーションマルチタスク.
カーネルスレッドとは、カーネルがスレッドのスケジューリングを完了するためにカーネルの参加が必要であることを意味します.オペレーティングシステムのコアに依存し、カーネルの内部要件によって作成および取り消されます.この2つのモデルにはメリットとデメリットがあります.ユーザスレッドは追加のカーネル支出を必要とせず、ユーザ状態スレッドの実現方式は特殊なアプリケーションの要求に適応するためにカスタマイズまたは修正することができるが、1つのスレッドがI/Oのために待機状態にある場合、プロセス全体がスケジューラによって待機状態に切り替えられ、他のスレッドは実行の機会を得られない.カーネルスレッドには制限がなく、マルチプロセッサの同時優位性を発揮するのに役立ちますが、より多くのシステムコストがかかります.
転載先:http://zhangwenxin82.blog.163.com/blog/static/114595956201211493426236/