プロセスはまた、それを通す必要がありましたなぜスレッド?、その違いは何ですか?どのような利点がスレッドを使用していますか?ありますマルチスレッドなどのスレッド、相互排他間の同期は、これらのことは、この記事で説明します方法として、詳細の一部をプログラミング。私は、このような顔の質問を参照してください。
?以下の機能をプログラムするなどおなじみなどのプログラミング技術をPOSIXに精通しているマルチスレッド化されています。
1)0のint型g_Flag初期値のグローバル変数があります。
2)メインスレッド1では、1スタート、印刷、およびg_Flagセット「これはスレッド1である」と
3)メインラインで、2に、スレッド2を開始する「これはスレッド2が」印刷、およびg_Flag前記
4)行1スレッドが終了した後2プログラムを終了する必要があります
5)メインスレッドは、我々はこの記事では、この質問を開始するには1から2にg_Flagを検出し、または1から2から終了すると、終了した後、誰もがそれを行うだろう。フレーム以下のとおりです。
1、プロセスおよびスレッド
2、理由のスレッドを使用
図3に示すように、スレッドの動作に関連する機能
4つのスレッド間の相互排他
スレッド間の同期5
6、最終的なコードの質問
1、プロセスおよびスレッド
プロセスは、プログラムが実行されるとき、それはプログラムの実装であることは、インスタンスで一緒にどの程度のデータ構造をもたらすことでした。ビューのカーネルの観点から、プロセスの目的は、システムリソースの割り当ての基本単位(CPU時間、メモリ、等)として機能することです。
スレッドは、フロー実行プロセスは、独立して動作することができる基本的な単位のプロセスよりも小さいCPUスケジューリングとディスパッチの基本単位です。複数のスレッド、スレッドと他のスレッドからなるプロセスは、すべてのリソースが所有しているプロセスに属するプロセスを共有(データ構造のほとんどは、共有アプリケーションのユーザプログラム実行フローの多くの比較的独立しています)。
「プロセス - リソース割り当ての最小単位、スレッド - プログラム実行の最小単位」プロセスは、別個のアドレス空間を有し、プロセスがクラッシュした後、保護モードで他のプロセスに影響を与え、そしてスレッドは、単にプロセスではありません別の実行パス。スレッドは独自のスタックとローカル変数を持っていますが、スレッドが別のアドレス空間を持っていない、ダイのスレッドは、プロセス全体のダイスに等しいです、プログラムので、マルチプロセス、マルチスレッドプログラムよりも堅牢ではなく、スイッチングの過程では、リソースを大量に消費するよりも大きな、効率が悪くなります。しかし同時に要件の一部のみスレッドに、特定の変数の同時動作を共有する必要がために、プロセスが使用することはできません。
2、理由のスレッドを使用
我々はプロセスとスレッドの違いを知っている以上のことから、実際には、これらの違いはまた、我々はスレッドを使用する理由です。、プロセスは、別のアドレス空間を持っている(スレッドが同じプロセスアドレス空間でプロセスを共有する)は、別のアドレス空間をスレッドません:一般です。(以下は、Linuxでのマルチスレッドプログラミングからの抜粋です)
複数のスレッドやプロセスを使用する理由の1つは、それは非常に「質素な」マルチタスク動作モードで、比較されています。私たちは、Linuxシステムでは、新しいプロセスがそのコードセグメント、スタックおよびデータセグメントを維持するために、その別のアドレス空間、データテーブルの多数の確立に割り当てる必要があります開始することを知って、これは「高価な」マルチタスクであります作品。互いの間で同じアドレス空間を使用して、プロセス内で複数のスレッド上で実行されているが、シェアのほとんどのデータが、スレッドのスペースを開始し、それははるかに少ない、それがプロセス空間を開始するのにかかるよりもかかる、と、お互いにスレッドを切り替えます所要時間は、時間がプロセス間で切り替えるために必要とされるよりもはるかに少ないです。統計によると、一般的には、プロセスのコストがスレッドの約30倍のコストで、当然のことながら、特定のシステム上で、このデータは、大きな違いがあるかもしれません。
理由2は、スレッド間の通信を容易にするためにマルチスレッド機構を使用することです。異なるプロセスのために、それらは別個のデータ領域が、データ転送のみを通信手段により行うことができ、この方法は時間がかかり、不便なだけではありません。スレッドは、データは、スレッドが直接他のスレッドのために使用することができるので、それも便利速いだけではなく、同じプロセス内のスレッド間で共有データスペースのために、そうではありません。もちろん、データを共有することも、他の多くの問題をもたらしている、いくつかの変数は、同時に2つのスレッドによって変更することができない、いくつかのルーチンの文がされている静的データ、などのマルチスレッド化されたプログラムへの悲惨な打撃を持っている可能性が高くなりますどこで最も注目を必要としているマルチスレッドプログラムを書いている時点。
別に言及した利点は、上記のプロセスと比較しないから、マルチスレッドプログラムは、方法によって複雑マルチタスクなど、当然のことながら、以下の利点を有します。
アプリケーションのレスポンスを向上させます。このプログラムは、特に意味のあるグラフィカルなインターフェイス、操作に時間がかかる場合は、システム全体の運転を待ちますがあり、この手順ではない、キーボード、マウス、メニューへの対応、およびマルチスレッド技術の使用は、時間がかかりますでしょう新しいスレッドに配置された操作は、(時間がかかる)、あなたはこの厄介な状況を回避することができます。
マルチCPUシステムより効率的。スレッドの数が異なるCPU上の異なるスレッド上で実行されている、CPUの数よりも大きくないとオペレーティングシステムを確実にします。
プログラムの構造を改善します。長く複雑なプロセスが実行のいくつかの独立または半独立部分に複数のスレッドに分割すると考えることができ、そのようなプログラムは理解し変更するために有益であろう。
=============================
関数呼び出しから、プロセスは、フォーク()オペレーションを使用して作成され、スレッドはクローン()オペレーションを使用して作成されました。リチャード・スティーブンスマスターはこれを言いました:
フォークは高価です。メモリは、親から子へコピーされるすべての記述子が子に複製され、そして上のようにします。現在の実装では、子供が独自のコピーが必要になるまで子供に親のデータ空間のコピーを回避コピーオンライトと呼ばれる技術を使用しています。しかし、関係なく、この最適化の、フォークは高価です。
IPCはフォーク後、親と子の間で情報を渡すために必要とされます。子供は親のデータ空間のコピーで、すべての親の記述子のコピーを開始しますので、フォークの前に親から子へ情報を渡すことは、簡単です。しかし、親に子供からの情報を返すことは、より手間がかかります。
両方の問題とスレッドの助け。スレッドはプロセスよりも「軽量」であるため、スレッドは時々軽量プロセスと呼ばれています。つまり、スレッドの作成は、10〜100倍高速プロセスの作成よりもすることができます。
プロセス内のすべてのスレッドが同じグローバルメモリを共有しています。これは、簡単にスレッド間の情報の共有を行いますが、このシンプルさと一緒に同期の問題が来ます。
=============================
図3に示すように、スレッドの動作に関連する機能
#含める
int型のpthread_create(がpthread_t * TID、CONSTのpthread_attr_t * attrのボイド*(* FUNC)(void *型)、void *型のarg);
int型pthread_joinを(がpthread_t tidは、無効**状態)。
がpthread_t pthread_self(無効)。
int型pthread_detachの(がpthread_t TID)。
空pthread_exit(void *型の状態)。
pthread_createの成功リターン0、そうでなければExxxの(正の数)のためのスレッドを作成します。
がpthread_t * TID:タイプのスレッドIDはがpthread_t、通常、符号なし整数のpthread_createが成功した呼び出し、* tidで返されたポインタです。
CONSTのpthread_attr_t * attrの:属性の指定など、スレッドの優先順位として、スレッドの作成、初期スタックサイズ、デーモンかどうか。あなたは、私たちは通常、デフォルト値を使用している、デフォルト値を使用するためにNULLを使用することができます。
void *型(* FUNC)(void *型):関数ポインタFUNC、新しいスレッドを実行するために機能した後に作成されたときに指定します。
void *型の引数:関数スレッドの実行への引数。あなたが複数のパラメータを渡したい場合は、パッケージ構造に配置します。
それ以外の場合は、終了し、成功したリターン0にスレッドのExxxの(正の数)を待ってpthread_joinを。
がpthread_t TID:指定待機するスレッドID
無効**ステータス:ないNULL、戻り値は(状態は2つだけポインタパラメータも「価値 - の結果」として知られている理由である理由であるパラメータが!)の状態で指される空間に保存されているスレッド場合。
pthread_selfは、現在のスレッドのIDを返すために使用しました。
pthread_detachのバックグラウンド・プロセスは類似してなる端末からの処理として、状態から分離状態になるスレッドを指定するために使用されます。成功したリターン0、そうでない場合はExxxの(正の数)。スレッドの別々の状態に、スレッドが終了する場合には、それはすべてのリソースが完全に解放されるのです。それは状態から分離されていない場合や、スレッドはpthread_joinを呼び出し、別のスレッドまで、そのスレッドID、終了状態を保持しなければなりません。
プロセスは類似しており、我々はプロセスマネージャを開いたとき、これは、私はゾンビプロセスの状態が存在しなければならない理由です!多くの理由のゾンビがありました。pthread_exitスレッドは他のスレッドのスレッドがpthread_joinをすることにより、関数の戻り値を取得するように、戻り値を指定することができ、終了します。
void *型のステータス:ポインタスレッドの終了の戻り値。
後で、これらの機能を知って、私たちはこの記事が始まる疑問を達成しようとしています。
1)0のint型g_Flag初期値のグローバル変数があります。
2)メインスレッド1では、1スタート、印刷、およびg_Flagセット「これはスレッド1である」と
3)メインラインで、2に、スレッド2を開始する「これはスレッド2が」印刷、およびg_Flag前記
これは非常に単純なことです!!! 3:00ないコールpthread_createのスレッドを作成すること。コードは以下の通りであります:
/ *
* 1)0のint型g_Flag初期値のグローバル変数があります。
*
*メインスレッド1 2)、スタート、印刷「これはスレッド1である」、およびg_Flagセット1に言っ
*
* 3)には、メインスレッドは、2開始「これはスレッド2が」印刷、前記g_Flag 2
*
* /
#含める
#含める
#含める
#含める
#含める
int型g_Flag = 0;
void *型スレッド1(void *型)。
void *型スレッド2(void *型)。
/ *
プログラムが開始されたとき*、単一のスレッドが最初のスレッドまたはメインスレッドと呼ばれ、作成されます。
*追加のスレッドはpthread_createのによって作成されます。
*だから我々はちょうど)(メインに2つのスレッドを作成する必要があります。
* /
int型のmain(int型のargc、char型** ARGV)
{
printf( "メイン入力してください\ n" は);
がpthread_t TID1、TID2。
int型RC1 = 0、RC2 = 0;
RC2 =のpthread_create(&TID2、NULL、スレッド2、NULL);
もし(RC2!= 0)
printf( "%sのた:%d \ n" は、__ func__、はstrerror(RC2));
RC1 =のpthread_create(&TID1、NULL、スレッド1、&TID2)。
もし(RC1!= 0)
printf( "%sのた:%d \ n" は、__ func__、はstrerror(RC1));
printf( "メインを残す\ nは");
出口(0);
}
/ *
*スレッド1()pthread_createの後、スレッド1で実行されます()
*それはg_Flag = 1を設定します。
* /
void *型スレッド1(void *型のarg)
{
printf( "スレッド1 \ nと入力します。");
printf( "これは、g_Flagスレッド1である:%のD、スレッドIDは%U \ nは"、g_Flag、(unsigned int型)pthread_self())。
g_Flag = 1。
printf( "これは、g_Flagスレッド1である:%のD、スレッドIDは%U \ nは"、g_Flag、(unsigned int型)pthread_self())。
printf( "N \スレッド1休暇");
pthread_exit(0)。
}
/ *
*スレッド2()pthread_createの後、スレッド2によって実行されます()
*それはg_Flag = 2を設定します。
* /
void *型スレッド2(void *型のarg)
{
printf( "スレッド2 \ nと入力します。");
printf( "これは、g_Flagスレッド2である:%のD、スレッドIDは%U \ nは"、g_Flag、(unsigned int型)pthread_self())。
g_Flag = 2。
printf( "これは、g_Flagスレッド1である:%のD、スレッドIDは%U \ nは"、g_Flag、(unsigned int型)pthread_self())。
printf( "休暇スレッド2 \ N");
pthread_exit(0)。
}
これが完了する1)、2)、3)これらの3つの要件。コンパイルは次のような結果が実行されました:
ネッツキー@ Ubuntuの:〜/ワークスペース/ pthead_test $ gccの-lpthread test.cの
プログラムで使用する場合は、コンパイル時に、の#includeに加えて、ライブラリ機能をpthreadのと同様に-lpthreadオプションを追加します。
ネッツキー@ Ubuntuの:〜/ワークスペース/ pthead_test $ ./a.out
メインを入力します。
スレッド2入力します。
これは、g_Flagスレッド2である:0、スレッドIDは3079588720です
これは、g_Flagスレッド1:2、スレッドIDは3079588720です
スレッド2のまま
メインを残します
スレッド1入力します。
これは、g_Flagスレッド1:2、スレッドIDは3071196016です
これは、g_Flagスレッド1:1で、スレッドIDは3071196016です
スレッド1のまま
しかし、動作の結果は、必ずしも上記ではない、があってもよいです。
ネッツキー@ Ubuntuの:〜/ワークスペース/ pthead_test $ ./a.out
メインを入力します。
メインを残します
スレッド1入力します。
これは、g_Flagスレッド1である:0、スレッドIDは3069176688です
これは、g_Flagスレッド1:1で、スレッドIDは3069176688です
スレッド1のまま
または:
ネッツキー@ Ubuntuの:〜/ワークスペース/ pthead_test $ ./a.out
メインを入力します。
メインを残します
などなど。それは時にメインスレッド主な機能の終了、その機能を遂行緊急に来ることができているスレッド2スレッドスレッド1に応じて、ためにもよく理解されています。また、スレッドは、我々はいくつかの時間のための主要な関数が終了、スリープ()の前にある場合、それは、実行するスレッド2時間をスレッド1保証することができます!全体のプロセスのすべての他のスレッドに影響を与えますが存在する可能性があるので、検討するマルチスレッドプログラミングの問題です。
ご注意:私たちは、スレッド関数のスレッド1である、あなたは気づいている確信している()、スレッド2を実行する前に()pthread_exitと呼ばれています。私は、出口()を呼び出したりリターンは、その後どうなるのですか?それを自分で試してみてください!
pthread_exit()スレッドが終了するため、戻り値)は、他のスレッドのスレッド関数はpthread_joinを(により、戻り値を取得するように、指定することができます。
復帰は、関数の戻り値は、関数の戻り値だけのスレッドで、スレッドが終了します。
、すべての機能は、出口のプロセスにスレッド関数で呼び出して終了している場合、終了は、撤退の過程である!「4)ラインプログラムを終了するには、スレッド2の後に終了する1つの必要性を」ポイント4は、非常に簡単に解決することでもあるの機能スレッド1を終了するにはpthread_joinをOKを呼び出す前に。
4つのスレッド間の相互排他
g_Flagは、グローバル変数、スレッドスレッド1で、スレッド2が同時にそれを操作することができますので上記のコードは、前の4つの要求の問題に優れたソリューションであると思われる、それは本当!ではない、それは、スレッド1とスレッド2を保護するためにロックする必要があります仕事への排他的アクセス。ミューテックス - ここでは、どのようにロック保護について説明します。
ミューテックス:
使用ミューテックス(相互排他)スレッド実行順序。多くの場合、唯一のスレッドが複数のスレッドを同期させるために、コードのクリティカルセクションを実行していることを確実にすることによって、ミューテックス。ミューテックスは、シングルスレッドコードを保護することができます。相関関数演算ミューテックス次のように:
#含める
int型は、pthread_mutex_lock(pthread_mutex_t * mptr)。
int型pthread_mutex_unlockの(pthread_mutex_t * mptr)。
//どちらのリターン:エラー時には0がOKであれば、正Exxxの値
その後、ロック解除操作pthread_mutex_unlockの完了後に、重要なリソースの操作の前にロックするのpthread_mutex_lockの必要性。そして、その内の関数の最初の2つのパラメータとして、pthread_mutex_t型の変数を宣言する前に。具体的なコードは、第5節を参照します。
スレッド間の同期5
ポイント5 - 終了メインスレッドは1から2にg_Flagを検出し、又は2から1時間です。あなたは、スレッドの同期が条件変数を必要と!スレッド同期テクノロジを使用する必要があります。
条件変数:
利用条件変数は、アトミックのスレッドができ、特定の条件が真になるまで、これまでブロックします。常にミューテックスと一緒に条件変数を使用します。試験条件は、ミューテックス(相互排除)の保護の下で行われます。
条件がfalseの場合、スレッドは通常、条件変数でブロックし、アトミック状況の変化にミューテックスの待ちを解除しています。別のスレッドが条件を変更した場合、スレッドは、1つ以上のスレッドは、次の操作を行うのを待つように、関連する条件変数をシグナリングすることができます。
モーニングコール
もう一度mutexを獲得
条件を再評価
以下の場合に、状態変数は、プロセス間で同期スレッドを使用することができます。
スレッドは、で書くことができるメモリに割り当てられています
プロセスを連携することにより、共有メモリ
「特定の条件は、これまで真になるまで条件変数がアトミックスレッドをブロックすることができる。」点5ために使用される、2から1に1から2にg_Flagを待つ、または、メインスレッドをブロックの主な機能。条件変数の相関関数は次のよう:
#含める
int型のpthread_cond_waitの(pthread_cond_t * CPTR、pthread_mutex_t * mptr)。
int型pthread_cond_signalを(pthread_cond_t * CPTR)。
//どちらのリターン:エラー時には0がOKであれば、正Exxxの値
特定の条件を待っているpthread_cond_waitのは、特定の条件が真である通知するために使用真、pthread_cond_signalをブロックされたスレッドです。発信者pthread_cond_t前に2つの機能は、これら二つの関数の型パラメータの変数を宣言する必要があります。
なぜ必ず使用条件変数一緒にミューテックスで、試験条件は、ミューテックス(相互排他)の保護下に行われ、それ?「機能条件」は、通常Aの複数のスレッド間で共有されているので変数。ミューテックスと、この変数は、異なるスレッドを検出するように設定することができることができます。
通常、単にスレッドの条件変数のウェイクを待ってpthread_cond_waitの。あなたが条件変数を待っている全てのスレッドをウェイクアップする必要がある場合は、呼び出します。
int型pthread_cond_broadcastの(pthread_cond_t * CPTR)。
次のデフォルト、ブロックされたスレッドは、あなたは一つの変数が真であることを知って、お待ちしております。あなたが時間を阻止する最大を設定したい場合は呼び出すことができます。
int型pthread_cond_timedwaitは(pthread_cond_t * CPTR、pthread_mutex_t * mptr、constの構造体TIMESPEC * ABSTIME)。
時間がアップしている場合は、条件変数が真ではない、まだ、戻り値ETIMEを返します。
6、最終的なコードの質問
次のように以前導入することにより、我々は簡単にコードを書くことができます。
/ *
?以下の機能をプログラムするなどおなじみなどのプログラミング技術をPOSIXに精通しているマルチスレッド化されています。
1)0のint型g_Flag初期値のグローバル変数があります。
2)メインスレッド1では、1スタート、印刷、およびg_Flagセット「これはスレッド1である」と
3)メインラインで、2に、スレッド2を開始する「これはスレッド2が」印刷、およびg_Flag前記
4)行1スレッドが終了した後2プログラムを終了する必要があります
1から2へ、又は2から1時間にプライマリスレッド終了g_Flag 5)検出
* /
#含める
#含める
#含める
#含める
#含める
; void *型(*楽しい)(void *型)のtypedef
int型g_Flag = 0;
静的pthread_mutex_tミューテックス= PTHREAD_MUTEX_INITIALIZER。
静的pthread_cond_t COND = PTHREAD_COND_INITIALIZER。
void *型スレッド1(void *型)。
void *型スレッド2(void *型)。
/ *
プログラムが開始されたとき*、単一のスレッドが最初のスレッドまたはメインスレッドと呼ばれ、作成されます。
*追加のスレッドはpthread_createのによって作成されます。
*だから我々はちょうど)(メインに2つのスレッドを作成する必要があります。
* /
int型のmain(int型のargc、char型** ARGV)
{
printf( "メイン入力してください\ n" は);
がpthread_t TID1、TID2。
int型RC1 = 0、RC2 = 0;
RC2 =のpthread_create(&TID2、NULL、スレッド2、NULL);
もし(RC2!= 0)
printf( "%sのた:%d \ n" は、__ func__、はstrerror(RC2));
RC1 =のpthread_create(&TID1、NULL、スレッド1、&TID2)。
もし(RC1!= 0)
printf( "%sのた:%d \ n" は、__ func__、はstrerror(RC1));
pthread_cond_waitの(&指揮、&ミューテックス)。
printf( "メインを残す\ nは");
出口(0);
}
/ *
*スレッド1()pthread_createの後、スレッド1で実行されます()
*それはg_Flag = 1を設定します。
* /
void *型スレッド1(void *型のarg)
{
printf( "スレッド1 \ nと入力します。");
printf( "これは、g_Flagスレッド1である:%のD、スレッドIDは%U \ nは"、g_Flag、(unsigned int型)pthread_self())。
(&ミューテックス)のpthread_mutex_lock。
もし(g_Flag == 2)
pthread_cond_signalを(&指揮);
g_Flag = 1。
printf( "これは、g_Flagスレッド1である:%のD、スレッドIDは%U \ nは"、g_Flag、(unsigned int型)pthread_self())。
pthread_mutex_unlockの(&ミューテックス)。
pthread_joinを(*(がpthread_t *)引数、NULL);
printf( "N \スレッド1休暇");
pthread_exit(0)。
}
/ *
*スレッド2()pthread_createの後、スレッド2によって実行されます()
*それはg_Flag = 2を設定します。
* /
void *型スレッド2(void *型のarg)
{
printf( "スレッド2 \ nと入力します。");
printf( "これは、g_Flagスレッド2である:%のD、スレッドIDは%U \ nは"、g_Flag、(unsigned int型)pthread_self())。
(&ミューテックス)のpthread_mutex_lock。
(g_Flag == 1)であれば
pthread_cond_signalを(&指揮);
g_Flag = 2。
printf( "これは、g_Flagスレッド2である:%のD、スレッドIDは%U \ nは"、g_Flag、(unsigned int型)pthread_self())。
pthread_mutex_unlockの(&ミューテックス)。
printf( "休暇スレッド2 \ N");
pthread_exit(0)。
}
結果は、要件を満たすために実行するようにコンパイルすることができます!
Linuxの基礎
http://www.makeru.com.cn/course/details/2058?s=45051
クイックスタートのlinux
http://www.makeru.com.cn/live/1758_310.html?s=45051
Linuxのマルチスレッドプログラミング
http://www.makeru.com.cn/course/details/1937?s=45051
線形および循環リストテーブルの応用
http://www.makeru.com.cn/course/details/1902?s=45051
スレッドプールの高い並行プログラミング