小さな書童観戦Threadスケジューリング

3360 ワード

PHPに去勢された私たちにとって、この話題を検討するのは実は少し骨が折れる.まず何がスケジューリングなのか、全国列車運営センターは全国の列車運行を管理し、スケジューリングし、いつ発車し、いつ車を譲り、いつ出発し、いつ目的地に到着するのか.列車スケジューリングセンターこれらの列車をスケジューリングするには、次の情報が必要です.列車番号(ID)、車は現在どこまで運行されていますか(status)、他の彼と同じ道を走っている車は現在どんな状態ですか(other_threads).....運営センターにすべての列車の情報があり、安定した環境(地震は発生しない)があれば、基本的にスケジューリング任務を完了することができます(もちろん、実際の状況はこれより複雑です).
オペレーティングシステムのスケジューリングは実際には列車のスケジューリングと似ており、各スレッドの状態を覚え、一定の戦略に基づいてこれらのスレッドをスケジューリングして各スレッドに与えられた使命を果たすことである.C/C++のマルチスレッドスケジューリングはオペレーティングシステムに基づいて行われる.スレッドのスケジューリングプロセスを明らかにするには、まず2つのことを理解します.ユーザースレッドとカーネルスレッドです.ユーザー・スレッドはサードパーティ・ライブラリまたはユーザー・ステータスが完了するスケジューリングであるためです.カーネルスレッドは、オペレーティングシステムのスケジューリングを使用してスケジューリングを完了します(作成も同じです).
では、まず、ユーザー・ステータス・スレッドがどのようにスケジューリングされているかを理解してから、カーネル・ステータス・スレッドがどのようにスケジューリングされているか、最後にユーザー・ステータス・スレッドとカーネル・ステータス・スレッドの間でどのようにインタラクションが完了しているかを理解しなければなりません.
カーネルスレッドがどのように作成されたかを見てみましょう.Linuxの発家史はlinux 2に教えてくれました.4スレッドの概念は導入されていませんが、2.4以降linux-kernelは軽量レベルのプロセス(つまり、私たちが言っているスレッド)を追加しました.スレッドとプロセスはlinuxにとってプロセスです.コアデータ構造はtask_であるためです.struct:
struct task_struct {

      struct thread_info *thread_info;  //              

      struct mm_struct *mm; //                

      struct mm_struct *active_mm; //        

      struct fs_struct *fs; //       

      struct file_struct *files; //     

      struct signal_struct *sinall; //    

      usigned_int pid; 

      usigned_int tid;

      usigned_int tgid;

      usigned_int pgid;

      usigned_int sid;

        ..... 

}

構造体には、プロセスまたはスレッドのすべての情報が格納されます.clone() --> do_fork() ---> copy_process(), copy_プロセス()は、現在のプロセスのtast_を作成してコピーします.struct、このサブプロセスのthread_を同時に作成info構造.task_structは、スケジューリングキューに格納され、キュー内のインデックス値、すなわちpidを返します.cloneの場合は、開いているファイル、ファイルシステム情報、信号処理関数、プロセスのアドレス空間をパラメータに基づいて共有するかどうかを選択します.これがプロセスとスレッドの違いの本質です.
カーネルスレッドのスケジューリングは、オペレーティングシステムのスケジューリングポリシーによって決定されます.オペレーティングシステムのスケジューリングポリシーには、時間分割スケジューリングポリシー、リアルタイムスケジューリングポリシーなどがありますが、ここでは説明しません.
ユーザスレッドがどのように作成されるかを見てみましょう.ユーザ状態スレッドの作成はpthreadライブラリが提供するAPI関数によって行われます.私たちが最もよく使うAPIは次のとおりです.
int   pthread_create( pthread_t *thread, const pthread_attr_t *attr, void* (*start_routine)(void*), void*arg );

int  pthread_cancel( pthread_t thread );

int  pthread_join( pthread_t **thread, void **retval);

int  pthread_detach( pthread_t  thread);

....
pthread_create関数の第1のパラメータthreadは、作成されたスレッドのIDを格納し、第2のパラメータpthread_attr_t *attrは、以下のような様々なスレッド属性をカスタマイズして存在する.
1) __detachstate:              ,      :
PTHREAD_CREATE_JOINABLE       ,PTHREAD_CREATE_DETACHED         ,           
2) __schedpolicy:       ,       ,        
...

3番目のパラメータはスレッドのエントリ関数の開始アドレスであり、4番目のパラメータはスレッドエントリ関数のパラメータである.入口関数のパラメータ伝達は1つのパラメータの場合に直接伝達することができ,複数のパラメータの場合には1つのstruct伝達に組み立てることができる.pthread_createは、最終的にclone関数を呼び出してスレッド:__pthread_create_2_1 -> create_thread() -> do_cloneを作成し、do_cloneに渡されるタグはCLONE_VM , CLONE_FS , CLONE_FILESである.pthread_cancel,pthread_join,pthread_detach関数は、スレッドを管理するプロセスとスレッドを作成するプロセスの関係であり、作成されたnスレッドがどのようにスケジューリングされるかについては、pthreadライブラリがユーザ状態スレッドスケジューリングポリシーを与える必要があります.例えば、ユーザ状態スレッドは長い間カーネル操作を開始しているが、ユーザ状態スレッドはCPUを占有してカーネルの戻りを待っているのだろうか.それとも、現在のスレッドの状態を覚えてから他のスレッドの実行を切り替え、カーネルが戻ってから前のスレッドをスケジュールしてから実行を続行しますか?それとも他の戦略ですか?