Linux の記事 [11]: Linux のスレッド <序文>

目次

1. Linux でのスレッド

1. Linux でのスレッドの概念

(1) 教材における大まかなスレッドの定義

(2) スレッドの紹介

(3) スレッドの実際の定義と概略図

 (4) LinuxやWindowsなど他のOSでのスレッドの比較

(5)LWP

(6) 軽量プロセスIDとプロセスIDの違い

2. プロセスを再定義する

軽量プロセスの説明:

(1) スレッドのメリット

(2) スレッドのデメリット

(3) スレッド例外

(4) スレッドの使用方法

3. スレッドおよびプロセスの共有/プライベートリソース

4. プロセスとスレッドの関係

2. ページテーブルの理解 - 仮想アドレスと物理アドレス間の変換

1. ページテーブルの理解

2. ページテーブルの利点

3. スレッドインターフェース

1.pthread_create はスレッドを作成します

ps -aL (all light) は、すべての軽量プロセスを表示します。

デモを終了するには戻る

2.pthread_self

3.thread_join 

4.pthread_exit

(1) pthread_exit と exit の比較

(2) スレッド出口には次の 3 種類があります。

pthread_exit デモを終了します

5.pthread_cancel

pthread_cancel(tid); 終了

4. ユーザーレベルのスレッドの概念

1. スレッドが異常な場合はどうすればよいですか? - スレッドの堅牢性の問題

2. pthread_t を理解する

3. スレッドスタック

 (1) コードエリアには3種類のコードがあります

(2) スレッドを作成する pthread_create の戻り値 pthread_t について説明する

(3) スレッドローカルストレージ

5. スレッドを分ける

1.コンセプト

2. 例

(1) pthread_ detach(pthread_ self()); 新しいスレッドは自己切り離されます。

(2) pthread_detach(tid1); メインスレッドが新しいスレッドを分離します

3. スレッドの分離は、スレッドが終了する 4 番目の方法として理解できます。


1. Linux でのスレッド

1. Linux でのスレッドの概念

(1) 教材における大まかなスレッドの定義

1. プロセス内で実行される実行フロー (スレッドはプロセスの仮想アドレス空間で実行されます)
2. スレッドはプロセスよりも細かく、低コストです
3. スレッドは CPU スケジューリングの基本単位です

(2) スレッドの紹介

フォーク後、父と息子はコードを共有します。if
else で判断できるため、父と息子のプロセスは異なるコードブロックを実行できます --> 異なる実行フローにつながり、特定のリソースを分割できます

(3) スレッドの実際の定義と概略図

 スレッド (実行フロー) はシステム スケジューリングの基本単位です。Linux には実際のスレッドは存在せず、Linux スレッドは軽量プロセスと呼ばれるプロセスによってシミュレートされます。スレッドの実行はプロセスよりも細かく、スケジューリングコストが低くなります(プロセスを切り替えるときにページテーブルや電気的アドレス空間などを切り替える必要はなく、スレッドのコンテキストデータを切り替えるだけで済みます)。プロセスの一部を実行し、プロセスのデータの一部を使用してプロセスのリソースの一部にアクセスするためです。

 (4) LinuxやWindowsなど他のOSでのスレッドの比較

Linux では次のように考えられます。 

プロセスとスレッドの間に概念的な違いはなく、両方とも実行ストリームと呼ばれます。
Linux スレッドはプロセスでシミュレートされます(実際にはプロセス PCB でシミュレートされます)

Linux 上の tcb は、論理構造が同じであるため、pcb です。

他のオペレーティング システム (Windows など) では、次の点が考慮されます。

プロセスとスレッドは実行フローのレベルで異なります。TCB 構造の追加は保守コストの増加につながります。 スレッド:
process=n:1 プロセス - PCB; スレッド - TCB (スレッド制御ブロック)

これで、CPU が認識するすべての task_struct が実行フロー (スレッド) になります。

(5)LWP

LWP - ライトウェイトプロセス: 軽量プロセス。LWP=PID の実行フローはメインスレッドであり、一般にプロセスとして知られています。

詳細概念: LWP は軽量プロセスです。Linux では、プロセスはリソース割り当ての基本単位であり、スレッドは CPU スケジューリングの基本単位であり、スレッドはプロセス PCB 記述を使用して実装され、すべての PCB は同じプロセス内にあります。同じ仮想アドレス空間を共有するため、従来のプロセスよりも軽量です

(6) 軽量プロセスIDとプロセスIDの違い

Linux の軽量プロセスは PCB であるため、各軽量プロセスには独自の軽量プロセス ID (PCB 内の PID) があり、同じプログラム内の軽量プロセスは共通のスレッド グループ ID を持つスレッド グループを形成します。

2. プロセスを再定義する

かつて: プロセス - カーネル データ構造 + プロセスに対応するコードとデータ
現在: プロセス - カーネル パースペクティブ:システム リソースの割り当てを担当する基本エンティティ(プロセスの基本属性)、つまり、リソースを適用する基本単位システム!

内部に実行フロー task_struct を持つプロセスは 1 つだけ —単一の実行フロー プロセス
内部に複数の実行フロー task_struct を持つプロセス —複数の実行フロー プロセス
        スレッド (実行フロー) がスケジューリングの基本単位です。

以下の紫枠で囲ったプロセスPCB、仮想メモリ、ページテーブル、メモリ内のデータとコード、このリソースの集まりをプロセスと呼びます。

軽量プロセスの説明:

task_ struct <= 従来のプロセス PCB、単一実行フロー プロセス (task_ struct が 1 つだけ) の場合、task_ struct = 従来のプロセス PCB、複数実行フロー プロセス task_ struct < 従来のプロセス PCB

(1)スレッドのメリット

新しいスレッドを作成する方が、新しいプロセスを作成するよりもはるかに安価です
プロセス間の切り替えと比較して、スレッド間の切り替えに必要なオペレーティング システムの作業ははるかに少なくなります。
スレッドはプロセスよりもはるかに少ないリソースを消費します
並列化可能なマルチプロセッサの数を最大限に活用できる
遅い I/O 操作が終了するのを待っている間、プログラムは他のコンピューティング タスクを実行できます。
計算集約型のアプリケーションは、マルチプロセッサ システムで実行するために、計算を複数のスレッドに分解して実装します。
I/O 集中型のアプリケーションの場合、パフォーマンスを向上させるために、I/O 操作が重複します。スレッドは、さまざまな I/O 操作を同時に待機できます。

マルチスレッドを使用すると、CPU リソースを最大限に活用し、タスク処理をより効率的にし、プログラムの応答を改善できます。つまり、時間のかかる操作ではスレッドを使用してアプリケーションの応答を改善します。

マルチコア CPU の場合、各コアはプログラム処理用の独立したレジスタのセットを備えているため、複数の実行フローの情報を異なるコアにロードして同時に並列実行することができ、CPU リソースを最大限に活用して処理を向上させることができます。マルチ CPU システムでは、CPU 使用率を向上させるためにスレッドが使用されます。CPUスレッドが個別にプログラムを実行できるようにするのではなく、CPU スレッド スケジューラ内の異なるスレッドがプログラム全体を一緒に実行します。

(2)スレッドのデメリット

パフォーマンスの損失
外部イベントによってめったにブロックされない、計算集約型のスレッドは、多くの場合、同じプロセッサを他のスレッドと共有できません。計算負荷の高いスレッドの数が利用可能なプロセッサよりも大きい場合、大幅なパフォーマンスの損失が発生する可能性があります。ここでのパフォーマンスの損失とは、利用可能なリソースが変化しないまま、追加の同期とスケジューリングのオーバーヘッドが追加されることを指します。
堅牢性の低下
マルチスレッドを記述するには、より包括的で深い検討が必要です。マルチスレッドプログラムでは、時間配分のわずかなずれや、共有すべきでない変数の共有によって悪影響を及ぼす可能性が高くなります。つまり、スレッド間の保護はありません。彼ら。
アクセス制御の欠如
プロセスはアクセス制御の基本的な粒度であり、スレッド内で特定の OS関数を呼び出すと 、プロセス全体に影響します。
プログラミングの難易度が上がる
マルチスレッド プログラムの作成とデバッグは、シングルスレッド プログラムよりもはるかに困難です

(3)スレッド例外

単一のスレッドがゼロで除算すると、ワイルド ポインタの問題によりスレッドがクラッシュし、プロセスもクラッシュします。
スレッドはプロセスの実行ブランチであり、スレッドが異常になると、プロセスの異常と同様に、プロセスを終了するシグナル メカニズムがトリガーされ、プロセスが終了します。
プロセス内のすべてのスレッドはすぐに終了します

(4)スレッドの使用方法

マルチスレッドを合理的に使用すると、 CPU 負荷の高いプログラムの実行効率が向上します。
マルチスレッドを合理的に使用すると、 IO 集約型プログラムのユーザー エクスペリエンスを向上させることができます (たとえば、日常生活では、コードを作成するときに開発ツールをダウンロードします。
マルチスレッド操作の現れ)

3. スレッドおよびプロセスの共有/プライベートリソース

プロセスはリソース割り当ての基本単位であり、スレッドはスケジューリングの基本単位です (システム内にスレッドがあるかどうかに関係なく、プロセスはリソースを持つ独立した単位です)。
プロセスの複数のスレッドは同じアドレス空間を共有するため、 テキスト セグメント データ セグメント は共有されます 関数を定義する 各スレッドで呼び出すことができます。 グローバル変数を定義すると 各スレッドでアクセスできます さらに 各スレッドは次のプロセス リソースと環境も共有します: ファイル記述子テーブル、各信号の処理モード (SIG_IGN SIG_DFL 、またはカスタム信号処理関数 )、現在の作業ディレクトリ、ユーザー ID およびグループ ID
スレッドはプロセス データを共有しますが、スレッド ID、 レジスタのセット、 スタック、 エラー番号、シグナル マスク ワード、スケジューリング優先度などの 独自のデータ部分もあります (複数のスレッドはそれぞれ独自のスタック領域を持ちますが、ヒープ領域は共有されます。各スレッドは、スタック スペース 共有するのではなく、 プロセスの仮想アドレス スペースに比較的独立したスタック スペースを割り当てます。 これにより、ランタイム スタックが混乱します )

4.プロセスとスレッドの関係

① Linux でプロセスがスレッドより安全である理由は、各プロセスが独立した仮想アドレス空間を持ち、各プロセスが独自のデータを持ち、独立していてデータを共有しないためです。この記述は誤りであり、広範すぎ、一方的です。

複数のプロセス間でのデータ共有は、マルチスレッドプログラミングよりも複雑ですスレッド間の通信は単純です (アドレス空間とページ テーブル情報を共有するため、パラメーターとグローバル データを通信できます)。一方、異なるプロセス間の通信はより複雑で、通常、これを実現するにはカーネル (システム コール) を呼び出す必要があります。

マルチスレッドの作成、切り替え、破棄はマルチプロセスよりも高速です。プロセス内のリソースのほとんどはスレッド間で共有されるため、共有データを再作成したり破棄したりする必要がないため、消費量はプロセスの消費量よりも少なく、逆も同様で、プロセスよりも高速です。

計算量が多い場合はマルチスレッドが望ましい。複数プロセス、複数スレッドを使用することで大量の計算を並列・同時処理できますが、スレッドのリソース消費量は複数プロセスに比べて少なく、安定性は複数プロセスに比べて劣るため、具体的でより詳細な需要シナリオについて

「プロセスには少なくとも 1 つのスレッドがある」は正しいですが、「プログラムには少なくとも 1 つのプロセスがある」は間違いですプログラムは静的でプロセスを含まないからです。プロセスはプログラムが実行されているときの実体であり、それはプログラムの実行です

スレッド自体はシステムリソースを所有しません。プロセスがリソース割り当て単位であるため、スレッドはシステム リソースを所有しませんが、プロセスのリソースを共有し、プロセスのリソースはシステムによって割り当てられます。

⑦どのスレッドも別のスレッドを作成または取り消すことができます。

コントラストの寸法

マルチプログレス

マルチスレッド化

要約する

データ共有、同期

データ共有は複雑であり、IPC が必要ですが、データは分離されており、同期は簡単です

プロセスデータを共有するためデータ共有は簡単ですが、その分同期が複雑になります

それぞれに独自の利点があります

RAM、CPU

大量のメモリを占有し、スイッチングが複雑で、CPU 使用率が低い

メモリ占有量が少なく、切り替えが簡単、CPU 使用率が高い

スレッドドミナント

作成、破壊、切り替え

作成、破棄、切り替えが複雑で時間がかかる

作成、破棄、切り替えはシンプルかつ高速です

スレッドドミナント

プログラミング、デバッグ

プログラムもデバッグも簡単

プログラミングは複雑、デバッグも複雑

プロセス優位

信頼性

プロセスは相互に影響を与えません

スレッドがハングするとプロセス全体がハングします。

プロセス優位

配布された

マルチコア、マルチマシン分散に適応します。1 台のマシンでは不十分な場合は、複数のマシンに拡張するのが簡単です。

マルチコア分散への適応

プロセス優位

2. ページテーブルの理解 - 仮想アドレスと物理アドレス間の変換

1. ページテーブルの理解

変換処理中に仮想アドレスは直接変換されません 仮想アドレスは
32 ビットです: 32 ビットを 10+10+12 に分割します 
0101 0101 00 0100 0111 11 0000 1110 0101
XXXX XXXX xx yyyy yyyy    yy zzzz zzzz zzzz

仮想アドレスの最初の 10 ビットは、第 1 レベルのページ テーブル (ページ ディレクトリ) で対応する第 2 レベルのページ テーブルを見つけます。対応する第 2 レベルのページ テーブルを見つけた後、中間の 10 ビットは、第 2 レベルのページ テーブルで対応するページ開始アドレスを見つけます。 -レベル ページ テーブル (物理メモリ); 対応するページの開始アドレスを見つけた後、物理メモリ内のページ (4KB) 内の対応するデータのアドレスを見つけるためのオフセットとして最後の 12 ビットが使用されます。12 ビットには 2^12=4096 ワードのセクション = 4KB があり、物理メモリ管理単位だけがページであり、ページは 4KB であるため、最後の 12 ビットはページのすべてのアドレスをカバーできます。アドレスを見つけた後、CPU は物理メモリのデータを読み取ります。

  

2. ページテーブルの利点

(1) プロセスの仮想アドレス管理とメモリ管理、ページテーブル + ページによる分離
(2) 省スペース: ページング機構 + ページテーブルのオンデマンド作成

ページ テーブルもメモリを占有します。ページ テーブルは分離されており、ページ テーブルはオンデマンドで作成できます。たとえば、ページ ディレクトリの 3 番目のアドレスは一度も使用されていないため、対応する 2 次ディレクトリを作成することはできません。必要に応じて作成されます。ページ テーブルのサイズは 2^32/2^12=2^20 バイト (ページ ディレクトリとセカンダリ ページ テーブル)

仮想アドレスから物理アドレスへの変換 - ソフトウェア (ページ テーブル) とハードウェア (MMu) を組み合わせたハードウェア MMU によって実行されます。

3. スレッドインターフェース

1.pthread_create はスレッドを作成します

pthread_create はライブラリ関数であり、ユーザー状態でユーザースレッドを作成する機能であり、このスレッドの実行スケジューリングは軽量プロセス LWP に基づいて実現されます。

新しいスレッドを作成するインターフェイスはシステム インターフェイスではなく、 linux によってもたらされるネイティブため、メイクファイル g++ -o $@ $^ -lpthread でリンクする必要があるサードパーティ ライブラリ関数です。 -std=c++ 11

 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); (pthread_t 就是unsigned long int

thread : 出力パラメータ、スレッド ID。attr : スレッド属性。現在は考慮されていません。nullptr に設定されます。start_routine : スレッド実行時のコールバック関数 (スレッドによって実行される関数メソッド)。arg: このパラメータを通じてスレッドの属性を渡します - 現在渡せる属性: 「作成されるスレッドの名前」、arg は start_routine関数の仮パラメータに渡されます

戻り値: 成功した場合は 0 を返し、失敗した場合はエラー コード errno を返します。 

例: int n = pthread_create(&tid, nullptr, startRoutine, (void *)"thread1"); 新しいスレッドは startRoutine 関数から実行に入り、メインスレッドは n を取得して次のコードの実行を継続します。

ps -aL (all light) は、すべての軽量プロセスを表示します。

LWP——軽量待機プロセス: LWP は軽量プロセスであり、プロセス内の PCB を記述します。

メイクファイル: 

mythread:mythread.cc
	g++ -o $@ $^ -lpthread -std=c++11
.PHONY:clean
clean:
	rm -f mythread

 mythread.cc

デモを終了するには戻る

#include<cstdio>
#include<unistd.h>
#include<pthread.h>
#include<iostream>
using namespace std;
void printTid(const char* name,const pthread_t &tid)//引用
{
    printf("%s 正在运行,thread id:0x%x\n",name,tid);
}

void* startRoutine(void* args)
{
    const char* name=static_cast<const char*>(args);
    int cnt=5;
    while(true)
    {
        printTid(name,pthread_self());
        sleep(1);
        if(!(cnt--))
            break;
    }
    cout<<"新线程退出…………"<<endl;
    return nullptr; 
}
int main()
{
    pthread_t tid;
    int n=pthread_create(&tid,nullptr,startRoutine,(void*)"thread 1");
    sleep(10);
    pthread_join(tid,nullptr);
    while(true)
    {
        printTid("main thread",pthread_self());
        sleep(1);
    }
    return 0;
}

2.pthread_self

 man 3 pthread_self

 pthread_t pthread_self(void);

スレッドは独自のスレッド ID を取得します

3.thread_join 

 man 3 pthread_join

int pthread_join(pthread_t thread, void **retval); thread: スレッド ID。retval: 出力パラメータ、スレッド終了の終了コード。(参加には終了信号は必要ありません)

スレッドが終了すると、通常は参加して待機する必要がありますが、参加しないとプロセスと同様のメモリ リークの問題が発生します。(つまり、関数は次のとおりです: スレッド リソースの解放 - スレッドが終了することが前提です。そして、スレッドに対応する終了コードを取得します)

成功した場合は 0 を返し、エラーの場合はエラー コードを返します。

4.pthread_exit

スレッドを終了します。スレッドの終了 - 通常の終了のみが考慮されます

(1) pthread_exit と exit の比較

exit(1):プロセスを終了することを意味し、メイン/新規スレッドが exit を呼び出すと、プロセス全体が終了することを意味します。pthread_exit() は単にスレッドを終了することを意味します。

(2) スレッド出口には次の 3 種類があります。

1. スレッドの終了方法、return —— return (void*)111;

2. スレッドの終了方法、pthread_exit —— pthread_exit((void*)1111);

3. スレッド終了メソッド: スレッドキャンセル要求、pthread_cancel —— pthread_cancel(tid);

void pthread_exit(void *retval); retval: スレッド終了コード

pthread_exit デモを終了します

#include<cstdio>
#include<unistd.h>
#include<pthread.h>
#include<iostream>
using namespace std;
void printTid(const char* name,const pthread_t &tid)//引用
{
    printf("%s 正在运行,thread id:0x%x\n",name,tid);
}

void* startRoutine(void* args)
{
    const char* name=static_cast<const char*>(args);
    int cnt=5;
    while(true)
    {
        printTid(name,pthread_self());
        sleep(1);
        if(!(cnt--))
            break;
    }
    cout<<"新线程退出…………"<<endl;
    //return nullptr; 
    pthread_exit((void*)1111);
}
int main()
{
    pthread_t tid;
    int n=pthread_create(&tid,nullptr,startRoutine,(void*)"thread 1");
    sleep(10);
    pthread_join(tid,nullptr);
    while(true)
    {
        printTid("main thread",pthread_self());
        sleep(1);
    }
    return 0;
}

5.pthread_cancel

スレッドをキャンセルする

int pthread_cancel(pthread_t スレッド); スレッド:回線ID

スレッドが終了する方法は、スレッドにキャンセル要求を送信します。スレッドがキャンセルされた場合、終了結果は -1 になります。

pthread_cancel(tid); 終了

#include<cstdio>
#include<unistd.h>
#include<pthread.h>
#include<iostream>
using namespace std;
void printTid(const char* name,const pthread_t &tid)//引用
{
    printf("%s 正在运行,thread id:0x%x\n",name,tid);
}

void* startRoutine(void* args)
{
    const char* name=static_cast<const char*>(args);
    int cnt=5;
    while(true)
    {
        printTid(name,pthread_self());
        sleep(1);
        if(!(cnt--))
            break;
    }
    cout<<"新线程退出…………"<<endl;
    //return nullptr; 
    //pthread_exit((void*)1111);
}
int main()
{
    pthread_t tid;
    int n=pthread_create(&tid,nullptr,startRoutine,(void*)"thread 1");
    sleep(10);
    pthread_cancel(tid);
    (void)n;
    cout<<"new thread been canceled"<<endl;
    void* ret=nullptr;  //void* -> 64 -> 8byte ->空间
    pthread_join(tid,&ret); //void **retval是 一个输出型参数
    cout<<"main thread join success,*ret:"<<(long long)ret<<endl;
    sleep(3);
    return 0;
}

4. ユーザーレベルのスレッドの概念

オペレーティング システムのカーネルがスレッドを認識しているかどうかに応じて、スレッドはカーネル スレッドユーザー スレッドに分類できますユーザーレベルのスレッドは、アプリケーションによってサポートされるスレッドによって実装され、カーネルはユーザーレベルのスレッドの実装を認識しませんカーネルレベルのスレッドは、カーネル (システム) によってサポートされるスレッドとも呼ばれます。

1. スレッドが異常な場合はどうすればよいですか? - スレッドの堅牢性の問題

スレッドが異常 --> プロセス全体が全体として異常終了します。スレッド例外 == プロセス例外
スレッドは他のスレッドの動作に影響します - 新しいスレッドはメインスレッドに影響します メインスレッド - 堅牢性/堅牢性が低い、

2. pthread_t を理解する

これはアドレスです
1. スレッドは独立した実行フローです
2. スレッドは、自身の実行プロセス中に一時データを生成します (関数の呼び出し、ローカル変数の定義など) 新しいスレッドでグローバル変数を変更した後、新しいスレッドとメインスレッド 変更された結果を確認できます
3. スレッドは独自の独立したスタック構造を持っている必要があります

3. スレッドスタック

 (1) コードエリアには3種類のコードがあります

私たちが使用するスレッド ライブラリ、ユーザーレベルのスレッド ライブラリ、ライブラリの名前は pthread です

コード領域には 3 種類のコードがあります。

①自分で書くコード。

② ライブラリのインターフェースコード。(たとえば、ダイナミック ライブラリ libpthread.so はメモリに書き込まれ、ページ テーブルを通じてプロセスの共有領域にマッピングされます。コード領域内のライブラリ インターフェイス コードは、コードを実行するために共有領域にジャンプします)ライブラリ内で実行し、コード領域に戻って実行を続行します)

③ システムインターフェースコード。(IDによるユーザーの切り替え -> カーネル実行コード)

すべてのコード実行はプロセスのアドレス空間で実行されます。


(2) スレッドを作成する pthread_create の戻り値 pthread_t について説明する

ユーザーはスレッドを使用したいと考えていますが、OS にはスレッドの概念がなく、libpthread.so スレッド ライブラリが接続の役割を果たします。

共有エリア内: 

スレッドの実装全体がすべて OS に反映されるわけではありませんが、OS が実行フローを提供し、特定のスレッド構造はライブラリによって管理されます。ライブラリは複数のスレッドを作成できます -> ライブラリはスレッドも管理します -> 管理: まず組織内で説明します

struct thread_ info

        pthread_ t tidh .
        void *stack; //私有栈
        ……
}  

libpthread.so スレッド ライブラリは共有領域にマップされます。スレッドを作成するとき、スレッドスレッド コントロール ブロック内には、スレッドを説明する情報があります。内部には、mm_struct ユーザー空間内のスペース (スレッド スタック) へのポインタがあります。 。スレッドが正常に作成されると、pthread_t 型のアドレスが返され、pthread_t 型のアドレスには、共有領域内の対応するユーザーレベルのスレッドのスレッド制御ブロックの開始アドレスが格納されます。

 結論: メインスレッドの独立したスタック構造はアドレス空間のスタック領域を使用し、新規スレッドが使用するスタック構造はライブラリで提供されるスタック構造を使用します (このスレッドのスタックはライブラリによって保持され、空間は提供されます)のユーザー共有領域による)

Linux では、スレッド ライブラリ (ユーザーレベルのスレッド ライブラリ) とカーネルの LWP は 1:1 ( LWP (アナログ PID) - 軽量待機プロセス: 軽量プロセス番号です。LWP=PID の実行フローがメイン スレッドであり、通称として知られています)プロセス

(3) スレッドローカルストレージ

スレッドライブラリの構造体 struct thread_info には内部にスレッドを記述する情報が含まれており、 struct thread_info にはスレッドローカルストレージと呼ばれる領域もあります。機能: グローバル変数をプライベート化できます。

通常の状況では、グローバル変数は複数のスレッドによって同時に変更できます。

__thread を追加し、グローバル変数を各プロセスにコピーし、グローバル変数をプライベートにし、独自のグローバル変数を変更します。

5.スレッドを分ける

1.コンセプト

①デフォルトでは新規作成スレッドはjoin可能となっており、スレッド終了後にpthread_join操作を行わないとリソースが解放できずシステムリークが発生します。
スレッド分離: thread の戻り値を気にしない場合、join は負担ですが、このとき、スレッドが終了するときにスレッド リソースを自動的に解放するようにシステムに指示できます。
        int pthread_detach(pthread_t スレッド);
スレッド グループ内の他のスレッドがターゲット スレッドを分離するか、スレッド自体が分離する可能性があります
        pthread_detach(pthread_self());
スレッドが分離された場合、再度結合することはできません。結合可能と分離は矛盾しています。スレッドは 結合可能と分離の両方を行うことはできません。
 int pthread_detach(pthread_t スレッド);

2. 例

(1) pthread_ detach(pthread_ self()); 新しいスレッドは自己切り離されます。

sleep(1) がない場合、新しいスレッドがループし続ける状況が発生します。なぜなら、メインスレッドが最初に int n = pthread_join(tid1, nullptr); を実行する可能性があるため、このとき、新しいスレッドは pthread_detach によって分離されておらず、メインスレッドは常に pthread_join でブロックされて戻りません。

sleep(1) がある場合、新しいスレッドはまず pthread_detach を使用して自身を切り離します。メインスレッドの後に int n = pthread_ join(tid1, nullptr) を実行します; この時点で、新しいスレッドは pthread_detach によってデタッチされており、メインスレッドは pthread_join に直接エラー コードを返します。切り離された場合、再度接続することはできません

(2) pthread_detach(tid1); メインスレッドが新しいスレッドを分離します

メインスレッドは最初に新しいスレッドを分離し、次に pthread_join を行う必要があるため、メインスレッドで新しいスレッドを分離することをお勧めします。

3.スレッドの分離は、スレッドが終了する 4 番目の方法として理解できます。

(1) スレッドの分離には即時分離と遅延分離があり、スレッドが生きていることを確認する必要がある。スレッドの分離は、このスレッドの存続と消滅を気にしないことを意味します。スレッドの分離は、スレッド終了の 4 番目の方法 (遅延終了) として理解できます。

(2) メインスレッドの終了によってプロセスが終了したり、他のスレッドの動作に影響を与えたりすることはありません。プロセスは、プロセス内のすべてのスレッドが終了した場合にのみ終了します。—— 通常、スレッドを分離し、対応するメインスレッド(常駐メモリのプロセス)は終了しないようにします。

おすすめ

転載: blog.csdn.net/zhang_si_hang/article/details/127901437