C言語のマルチスレッド
マルチスレッドは、マルチタスクの特殊な形式で、マルチタスクは、コンピュータの実行に2つの以上のプログラムをみましょうことができます。一般に、マルチタスクの二種類:プロセスベースおよびスレッドベース。
- プロセスベースのマルチタスクは、プログラムの同時実行です。
- マルチタスク処理スレッドに基づいて、同じプログラムの並行断片を実行します。
マルチスレッドプログラムが同時に実行できる2つ以上の部品が含まれています。このようなプログラムの各部分は、それぞれが単一の実行経路を画定する、スレッドと呼ばれます。
このチュートリアルは、Linuxオペレーティングシステムを使用していると仮定し、私たちは、POSIXは、マルチスレッドC ++プログラムを記述使いたいです。API POSIXスレッドには、FreeBSDの、NetBSDの、GNU / Linux、Mac OS X、およびSolarisのように、多くの種類のUnix POSIXシステムに提供または利用可能のPthreadすることができます。
スレッドを作成します。
次のプログラムは、我々は、POSIXスレッドを作成するためにそれを使用することができます。
#include <pthread.hの>
のpthread_create(スレッド、ATTR、start_routineが、引数)
ここでは、pthread_createのは、 新しいスレッドを作成し、それを実行します。以下はパラメータの説明です:
参数 | 描述 |
---|---|
thread | 指向线程标识符指针。 |
attr | 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。 |
start_routine | 线程运行函数起始地址,一旦线程被创建就会执行。 |
arg | 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。 |
あなたが成功したスレッドを作成する場合は0の戻り値は、スレッドの作成に失敗したことを示している場合、この関数は、0を返します。
スレッドを終了
私たちは、POSIXスレッドを終了させるためにそれを使用することができ、次の手順を実行します。
書式#include <pthread.hの>
pthread_exit(ステータス)
ここでは、pthread_exitは、 明示的にスレッドを終了するために使用しました。スレッドが終了した後に作業を継続する必要がない場合、通常、pthread_exit()関数が呼び出されます。
)(メインはpthread_exitて終了するには、それが終了する前に作成し、そのスレッドは()である場合、他のスレッドが実行を継続します。そうでなければ、彼らは()が自動的にメインの終わりで終了します。
接続分離スレッド
私たちは、次の2つの関数を使用して接続するか、別のスレッドができます。
pthread_joinを(スレッドID、状態)
pthread_detachの(スレッドID)
指定されたスレッドID、スレッドが終了するまででpthread_join()サブルーチンは、呼び出し元のプログラムを妨げます。スレッドが作成されると、その属性は、それが(接合可能)または(デタッチ)着脱接続されているかどうかを定義します。定義されただけで接続することができます接続することができますスレッドを作成します。スレッドが作成されている場合は分離可能と定義され、それもなることはありません。pthread_joinを()関数は、完了スレッドを待ちます。
注意を払います
pthreadのライブラリがないのLinux システムのデフォルトのライブラリ、あなたが接続するために、ライブラリを使用する必要がある、libpthread.aを使用してpthread_createのスレッドが作成され、追加することでコンパイル-lpthread パラメータを:
gccのcreateThread.cは-lpthread - createThread.o oを
。/のCreateThread。
試験1スレッドプログラミングパスインスタンスパラメータなし
//スレッドベースの並行プログラミング // TEST_1のCreateThread する#include <stdio.hに> する#include <pthread.hの> / * *は、pthreadのライブラリは、Linuxシステムのデフォルトのライブラリではありません、あなたは接続libpthread.aライブラリを使用する必要があり、 *のpthread_createを使用してスレッドが作成されたとき、-lpthreadパラメータを追加することでコンパイル: * gccの-o createThread.o createThread.c -lpthread * ./createThread.o *プラス上の2つのコンパイルが成功し、その結果を出力した後、 * * / の#define NUM_THREADS 5 実行機能スレッドが// void *型printHello(void *型のArg) { のprintf( "スレッドの\ N-におけるCのこんにちは、世界!"); 0を返す; } int型のmain() { 私はint型、 int型RET; //定義ID変数スレッド、配列変数の複数 TIDS [NUM_THREADS]がpthread_t; (; IはNUM_THREADSを<; I ++はI = 0)のための { //パラメータは次のとおりスレッドID作成スレッドパラメータ、関数呼び出し、引数が渡された RET =のpthread_create(&TIDS [i]は、NULL、printHello、NULL); IF(RET = 0!) { のprintf( "pthread_createのエラー:ERROR_CODE = \ N-"); } } //打ち上げと他のスレッドの後には、エンドまでに処理 pthread_exit(NULL); 0を返す; } / * CLion(Ubuntuの中*出力)である 、こんにちはスレッドの世界でC! Cでのスレッドのこんにちは、世界! こんにちは、世界Cでのスレッドの! こんにちは、世界Cでのスレッドの! こんにちは、世界Cでのスレッドの! * * /
単純なパラメータ渡しスレッド同時プログラミング例の試験2
スレッドパラメータに送信//スレッドベースの並行プログラミング、。1 // Test_2_createThread する#include <stdio.hに> する#include <pthread.hの> する#include <stdlib.h>に含まれ ます。#define NUM_THREADS。5つの 実行機能スレッド// void *型PrintHelloId (*無効スレッドID) { //受信したパラメータがキャスト、ポインタが読んで、その後、非プラスチック製のポインタ型となり int型* TID =((INT *)のThreadIDを); のprintf(「こんにちは、世界、 %Dスレッドの\ N-」、TID)は、 0を返す; } int型のmain() { がpthread_tのpスレッドが[NUM_THREADS]; I、RCをint型、 iは配列に格納された値// INTインデックス[NUM_THREADS]; のための(I = 0。私はNUM_THREADSを<; Iは++) { のprintf( "(メイン)は:Dは、スレッド%を作成\ N-"、I); インデックス[I] = I; //は、iの値を保存します インデックス渡されたパラメータが型なしポインタであるとき//を変換する必要があります RC =のpthread_create(&pthreadsの[I]、NULL、PrintHelloId、(void *型)&インデックス[I]); IF(0 = RC!) { のprintf(「エラー:N- ");! \スレッドを作成できません 終了(-1); } } pthread_exit(NULL); 0を返す; } / * * CLionで(Ubuntuの)出力である )(メイン:スレッド0作成 (主に)。スレッド1作成 こんにちは、世界、スレッド0 主に():スレッド2が作成 こんにちは、世界、スレッド1 メイン():スレッド3が作成 こんにちは、世界、スレッド2 メイン():スレッド4を作成 こんにちは、世界、スレッド3 こんにちは、世界、スレッド4 * * /
試験3同時プログラミングスレッドのパラメータ例として渡される構造
//基于线程的并发编程、向线程传递参数2(传递结构体) // Test_3_createThread する#include <stdio.hに> する#include <pthread.hの> する#include <STDLIB.H> の#define NUM_THREADS 5 のtypedef構造体thread_data { int型スレッドID; チャーメッセージ。 } THDATA、* PTHDATA。 ボイド* PrintHello(ボイド* pthreadid) { PTHDATA TID =(PTHDATA)pthreadid。 printfの( "これはのPthreadです:%dの;情報:%Cの\ nを"、tid-> threadidは、tid->メッセージ); 0を返します。 } INTメイン(ボイド) { がpthread_tのPthread [NUM_THREADS]。 THDATA指数[NUM_THREADS]。 私はint型、RET; 用(i = 0; iはNUM_THREADSを<; iは++) { printf( "主は、():Dは、スレッド%を作成\ N-"、I); 指数[I] =私は.threadid、 インデックス[I] .message = '+ 10%I; RET =のpthread_create(&のPthread [I] 、NULL、printHello、(ボイド*)&インデックス[I]); IF = RET(0)! { "スレッドの\ N-の作成に失敗しましたエラー:!"のprintf(); 出口(-1); } } pthread_exit(NULL); 0を返す; } / * * CLionは(Ubuntuの)が出力されるに ()主要:スレッドを作成0 メイン():1スレッドを作成する。 0;情報:これはのPthreadである メイン():スレッドを生成2 )(メイン。糸3を作成する 。これは、のPthread:2;情報:Cの 主が():スレッド4を作成する これはのPthread :. 3である情報:D これはのPthreadです:4;情報:Eは、 これはのPthreadである:1;情報:B * * /
試験例4接続スレッドプログラミング
//並行プログラミングのスレッドベース、接続または別のスレッド // Test_4_createThread // 2019インディアン10越27 Riを午後2時45分11秒、まだ完全には理解していない の#include <stdio.hに> する#include <pthread.hの> <STDLIBする#include .H> の#define 5 NUM_Pthreadする。 ボイド* printHello(* pthreadidボイド) { INT * TID =((INT *)pthreadid); のprintf( "スレッドDの%眠る、... \ N-を出る"、TID); 0を返します; } int型メイン(ボイド) { IをINT、RET; ;のPthread [NUM_Pthread]がpthread_t のpthread_attr_tがATTRである; //スレッド属性定義 ボイド*ステータス、 INTインデックス[NUM_Pthread]; //初期化し、接続するスレッド設定 pthread_attr_init(&ATTR) ; pthread_attr_setdetachstate(&ATTR、PTHREAD_CREATE_JOINABLE)。 のprintf( "メイン():完全なスレッドID:%のD"、I)。 用(i = 0; iはNUM_Pthread <; iは++) { のprintf( "メイン():创建线程%D \ n"、I)。 インデックス[I] = I。 RET =のpthread_create(&のPthread [i]は、NULL、PrintHello、(ボイド*)&インデックス[I])。 } //删除属性、并等待其他线程 は、pthread_attr_destroy(&ATTR)。 用(i = 0; I <NUM_Pthread; iは++) { RET = pthread_joinを(のPthread [i]は、ステータス); (!0 = RET)の場合 { ( ":参加できない、%dは\ nのエラー"、RET);のprintf 出口(-1)。 } pthread_exit(NULL)。 printf( "ステータスで終了:%のPを\ n"、ステータス)。 } のprintf( "メイン():プログラム出\ n"); 0を返します。 }
セマフォメカニズム
試験5同期書き込みセマフォ
//同期信号の量 の#include <stdio.hに> する#include <pthread.hの> する#include <stdlib.h>に含ま 書式#include <string.hの> 書式#include <unistd.h> の#include <semaphore.h> #レン100 //入力されたコンテンツ長を設定定義 ; sem_t bin_sem チャーwork_area [レン]; //入力内容記憶 ボイド* Thread_func(ボイド*のArg) { //ウェイトセマフォが0と出口よりも大きな値を有する sem_wait(&bin_sem)のを、 しばらく(= 0 strncmpは( "終了"、work_area ,. 3)!) { のprintf( "N- \%のLD入力文字"は、strlenを(work_area)-1); } 戻り0; } int型メイン(ボイド) { int型RES; / /ストア命令の戻り値//処理スレッドの結果格納 //セマフォを初期化し、0の初期値を設定します のPthreadがpthread_t; //スレッドを作成 void *型thread_result; //ストアスレッドの処理結果 RES = sem_init(&bin_sem、0、0); IF(RES = 0!) { perrorは( "初期化がセマフォをfailes"); 出口(EXIT_FAILURE); } //新しいスレッド0を作成します。 RES =のpthread_create(&のPthread、NULL、Thread_func、NULL); IF(0 = RESを!) { perrorは( "スレッドの作成に失敗しました"); 出口(EXIT_FAILURE); } のprintf( "完了\ N-へ'末端'を入力します。"); //作業領域は、文字列の末尾の先頭でない場合、入力し続ける しばらく(0!= strncmpは(「終了」、work_area ,. 3)) { //標準の作業領域への入力を取得 するfgets(work_area、レン、STDIN)。 sem_post(&bin_sem); //セマフォ+1 } のprintf( "N \ \ nは終了するスレッドを待っています..."); //スレッドの終了を待つ RES = pthread_joinを(のPthread、&thread_result); もし(!= 0の解像度) { perrorは( "スレッドが失敗した参加"); 出口(EXIT_FAILURE)。 } のprintf( "スレッドが\ nを接合しました")。 sem_destroy(&bin_sem)。//销毁信号量 の出口(EXIT_SUCCESS); 0を返します。 }
試験6は、ミューテックス資源の重要な操作を実現します
//ミューテックスと同期 する#include <stdio.hに> する#include <pthread.hの> する#include <stdlib.h>に含ま 書式#include <string.hの> に#defineレン//計算の数を増加させます。3 の#define NUM_Pthread 5 //スレッド長の設定 int型のカウント= 1; //データセグメント内の共有リソース、複数のプロセスが重要なリソースをつかむために ミューテックス追加する必要があり、重要なリソースへの// pthread_mutex_tミューテックス= PTHREAD_MUTEX_INITIALIZERを; void *型Thread_func(void *型スレッドID) { INT TID = *((INT *)のThreadID); int型I、ヴァル; のprintf( "のPthread ID:%D \ N-"、TID) のための(I = 0;私は<NUM_Pthread; Iは++) { pthread_mutex_lockの(&ミューテックス) ; ヴァル= COUNT; のprintf( "%= \ N-ヴァルD"、ヴァル++); COUNT =ヴァル。 pthread_mutex_unlockの(&ミューテックス)。 } 0を返します。 } のIntメイン(ボイド) { int型RES、格納されたコマンドの//戻り値 Iがint型; //作成スレッド;のPthread [NUM_Pthread]がpthread_t INTインデックス[NUM_Pthread]; のための(I = 0;私は<NUM_Pthread; Iは++) { インデックス[i]は=私; //スレッドの作成 RESを=のpthread_create(&のPthread [i]は、NULL、Thread_func、(void *型)&インデックス[i])と、 IF(0 = RES!) { のprintf(「エラー:スレッドの作成に失敗しました。 !\ N- "); 出口(-1); } } のための(I = 0; I <NUM_Pthread; Iは++) { //スレッドマージ pthread_joinを(のPthread [I]、NULL); } のprintf(" %のDカウント= \ N」、カウント); pthread_exit(NULL)、 0を返します。 } //ミューテックスせずにこのプログラムを実行して、私たちが間違った答えを得るだけでなく、それぞれの時間は、答えは同じではありません //分析 //際に複数のスレッドのピアでプロセッサ上の特定の順序で、同時に、完全な機械語命令を実行するときに、各スレッドは、特定の順序で命令の並行実行が定義されています