Linuxプログラミング学習ノート|Linuxマルチスレッド学習[1]-スレッドの作成と基本制御


文章シリーズの原因
2017年の初め、私は自分に小さな目標を決めました:Linuxのプログラミングを勉強して、そしてネットを通じて自分の学習の心得を分かち合います.この小さな目標を達成するために、私は文章を書くことで私の学習心得を記録し始めました.年末には、Linux関連の学習ドキュメント24編を完成して、私の小さな目標を実現することを望んでいます.これはこのシリーズの最初の文章で、私が最近Linuxマルチスレッドを勉強した総括です.
スレッドとは
ウィキペディアがスレッドをどのように定義しているかを見てみましょう.
スレッド(英語:thread)は、オペレーティングシステムが演算スケジューリングできる最小単位です.プロセスに含まれ、プロセス内の実際の動作単位です.1つのスレッドとは、プロセス内の単一の順序の制御フローを指し、1つのプロセスで複数のスレッドを並列に実行することができ、各スレッドは異なるタスクを並列に実行します.Unix System VおよびSunOSでは軽量プロセス(lightweight processes)とも呼ばれるが、軽量プロセスはカーネルスレッド(kernel thread)を指し、ユーザスレッド(user thread)をスレッドと呼ぶことが多い.
1つのプロセスは、それぞれのコールスタック、独自のレジスタ環境(register context)、および独自のスレッドローカルストレージ(thread-local storage)を有する複数のスレッドを含むことができる.各スレッドは、異なるタスクを同時に実行します.まだプロセスに関する文章を書いていないので、ここではプロセスとスレッドの違いをさらに説明しません.プロセスまたは個別の文章でそれらの異同を説明します.
スレッドのライフサイクル
スレッドの4つのステータス
スレッドのライフサイクルには、準備、実行、ブロック、終了の4つのステータスがあります.次の表では、この4つのステータスを説明します.
≪ステータス|Status|emdw≫
意味
準備完了
スレッドは実行できますが、使用可能なプロセッサを待っています.
うんてん
スレッドは実行中です.マルチコアシステムでは、同時に複数のスレッドが実行される可能性があります.
ブロッキング
スレッドがプロセッサを待つ以外の条件
終了
スレッドが起動関数から返されるか、pthread_が呼び出されます.exit関数、またはキャンセル
スレッドは一定の条件でステータスを変換できます.次の図は、スレッドがステータスをどのように変換するかを示しています.
スレッドの作成
スレッドを作成するには、pthread_create()という関数を使用します.関数の説明は次のとおりです.
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);

args:
    pthread_t *thread              :             ,             thread        
    const pthread_attr_t *attr     :           
    void *(*start_routine) (void *):            (    )
    void *arg                      :                 

return: 
           ,0   , 0  

作成に成功したスレッドごとにスレッド番号があり、pthread_self()という関数でこの関数を呼び出すスレッドのスレッド番号を取得できます.pthread_XX()に関連する関数をコンパイルする必要がある場合は、コンパイル時に-pthreadを追加する必要があります.
スレッドの基本制御
スレッドの終了
スレッドを終了するには、通常、次の方法があります.
方法
説明
exit()
プロセス全体を終了し、プロセス全体のメモリ領域を解放します.
pthread_exit()
スレッドを終了しますが、分離されていないスレッドのメモリ領域は解放されません.
pthread_cancel()
他のスレッドは、現在のスレッドを信号でキャンセルします.exit()はプロセス全体を終了するので、スレッドを終了するために使用することはほとんどありません.pthread_cancel()およびpthread_exit()関数を用いてスレッドを終了する.ここでは、pthread_exit()という関数に重点を置きます.
void pthread_exit(void *retval);

args: 
    void *retval:           

return:
     

スレッドを終了するには、スレッド呼び出しの関数にpthread_exit(X)を追加するだけでよいが、1つのスレッドが非分離(デフォルトで作成されたスレッドは非分離)であり、pthread_join()を使用していない場合、スレッドが終了してもメモリ領域は解放されないことに特に注意する必要がある.これにより、このスレッドは「ゾンビスレッド」になります.ゾンビスレッドはシステムリソースを大量に消費するため、ゾンビスレッドの発生を回避します.
スレッドの接続
前のセクションでは、pthread_join()という関数について説明しました.このセクションでは、まずこの関数を見てみましょう.
int pthread_join(pthread_t thread, void **retval);

args:
    pthread_t thread:          
    void **retval   :                      
    
return:
           ,0   , 0   
pthread_join()が呼び出されると、呼び出されたスレッドが終了するまで、現在のスレッドは再実行されません.pthread_join()関数が返されると、呼び出されたスレッドは本当の意味での終了となり、呼び出されたスレッドが非分離である場合、メモリ領域も解放されます.ここで3つ注意しなければならないことがあります.
  • が解放されたメモリ領域はシステム領域にすぎません.malloc()が割り当てた領域など、プログラムが割り当てた領域を手動でクリアする必要があります.
  • スレッドは、1つのスレッドにのみ接続できます.
  • 接続されているスレッドは非分離でなければなりません.そうしないと、接続にエラーが発生します.

  • スレッドの分離
    前節では、pthread_join()について、pthread_join()を使用できるのは非分離スレッドだけだと述べました.この節では、スレッドの分離とは何かを見てみましょう.Linuxでは、1つのスレッドが接続可能であるか、分離可能であるかのいずれかです.スレッドを作成すると、スレッドのデフォルトは接続可能です.接続可能スレッドと分離可能スレッドには、次の違いがあります.
    スレッドタイプ
    説明
    接続可能スレッド
    他のスレッドによって回収または殺すことができ、殺す前にメモリスペースが自動的に解放されない
    分離可能スレッド
    他のスレッドによって回収または殺すことはできません.メモリ領域は、終了時にシステムによって自動的に解放されます.
    接続可能なスレッドでは、メモリ領域が自動的に解放されないことがわかります.したがって、このようなスレッドについては、pthread_join()関数を組み合わせて使用する必要があります.分離可能な関数では、pthread_join()関数は使用できません.スレッドを分離するには、1)スレッドのプロパティを変更して分離可能なスレッドにする方法と、2つの方法があります.2)関数pthread_detach()を呼び出すことによって、新しいスレッドを分離可能なスレッドにする.pthread_detach()関数について説明します.
    int pthread_detach(pthread_t thread);
    
    args:
        pthread_t thread:           
    
    return:
               ,0   , 0   

    スレッドを分離するスレッド番号を指定するだけで、接続可能なスレッドから分離可能なスレッドに変更できます.
    プライマリスレッド
    上記のセクションでは、スレッドの作成、終了、接続について説明します.このセクションでは、特殊なスレッド-プライマリスレッドを見てみましょう.Cプログラムでは、main(int argc, char **argv)がプライマリスレッドです.プライマリ・スレッドでは、通常のスレッドで可能なことを行うことができますが、プライマリ・スレッドが戻ったり、実行が終了したりすると、プロセスの終了が発生し、プロセスの終了がプロセス内のすべてのスレッドの終了につながるという大きな違いがあります.プライマリ・スレッドがすべてのスレッドを終了しないようにするには、以前に学んだ知識に基づいて、次のいくつかの解決策があります.
  • は、プライマリ・スレッドを戻したり終了させない(returnの前にwhile(1)文を追加する).
  • は、pthread_exit()を呼び出してメインスレッドを終了し、メインスレッドreturnの後、メモリ領域が解放される.
  • は、returnの前にpthread_join()を呼び出すと、接続されたスレッドの実行が終了するまでメインスレッドがブロックされ、実行される.

  • この3つの方法のうち、前の2つはあまり使われておらず、3つ目はよく使われる方法です.
    まとめ
    この文章は主にスレッドの基本概念,スレッドのライフサイクルと状態,スレッドの作成,終了,接続,分離およびメインスレッドを紹介した.次の記事では、マルチスレッドのポイントである同期について説明します.
    もし本文があなたに役に立つと思ったら、もっと支持してください.ありがとうございます.