まず例を挙げてみましょう。数値をインクリメントするために 2 つのスレッドを作成します。おそらくこの例には実用的な価値はありませんが、少し変更するだけで他の場所でも使用できます。
コード:
/*thread_example.c : c multiple thread programming in linux *author : falcon *e-mail : tunzhj03@st.lzu.edu.cn */ #include <pthread.h> #include <stdio.h> #include <sys/time.h> #include <string.h> #define max 10 pthread_t thread[2]; pthread_mutex_t mut; int number=0, i; void *thread1() { printf ("thread1 : i'm thread 1/n"); for (i = 0; i < max; i++) { printf("thread1 : number = %d/n",number); pthread_mutex_lock(&mut); number++; pthread_mutex_unlock(&mut); sleep(2); } printf("thread1 :主函数在等我完成任务吗?/n"); pthread_exit(null); } void *thread2() { printf("thread2 : i'm thread 2/n"); for (i = 0; i < max; i++) { printf("thread2 : number = %d/n",number); pthread_mutex_lock(&mut); number++; pthread_mutex_unlock(&mut); sleep(3); } printf("thread2 :主函数在等我完成任务吗?/n"); pthread_exit(null); } void thread_create(void) { int temp; memset(&thread, 0, sizeof(thread)); //comment1 /*创建线程*/ if((temp = pthread_create(&thread[0], null, thread1, null)) != 0) //comment2 printf("线程1创建失败!/n"); else printf("线程1被创建/n"); if((temp = pthread_create(&thread[1], null, thread2, null)) != 0) //comment3 printf("线程2创建失败"); else printf("线程2被创建/n"); } void thread_wait(void) { /*等待线程结束*/ if(thread[0] !=0) { //comment4 pthread_join(thread[0],null); printf("线程1已经结束/n"); } if(thread[1] !=0) { //comment5 pthread_join(thread[1],null); printf("线程2已经结束/n"); } } int main() { /*用默认属性初始化互斥锁*/ pthread_mutex_init(&mut,null); printf("我是主函数哦,我正在创建线程,呵呵/n"); thread_create(); printf("我是主函数哦,我正在等待线程完成任务阿,呵呵/n"); thread_wait(); return 0; }
最初にコンパイルして実行しましょう
引用:
falcon@falcon:~/program/c/code/ftp$ gcc -lpthread -o thread_example thread_example.c falcon@falcon:~/program/c/code/ftp$ ./thread_example 我是主函数哦,我正在创建线程,呵呵 线程1被创建 线程2被创建 我是主函数哦,我正在等待线程完成任务阿,呵呵 thread1 : i'm thread 1 thread1 : number = 0 thread2 : i'm thread 2 thread2 : number = 1 thread1 : number = 2 thread2 : number = 3 thread1 : number = 4 thread2 : number = 5 thread1 : number = 6 thread1 : number = 7 thread2 : number = 8 thread1 : number = 9 thread2 : number = 10 thread1 :主函数在等我完成任务吗? 线程1已经结束 thread2 :主函数在等我完成任务吗? 线程2已经结束
サンプル コードのコメントはより明確になるはずです。以下に引用します。上記のいくつかの関数と変数はインターネット上にあります。
引用:
スレッド関連の操作
一pthread_t
pthread_t はヘッダー ファイル /usr/include/bits/pthreadtypes.h で定義されています。
Typedef unsigned long int pthread_t;
スレッドの識別子です。
二pthread_create
関数 pthread_create はスレッドの作成に使用されます。そのプロトタイプは次のとおりです:
extern int pthread_create __p ((pthread_t *__thread, __const pthread_attr_t *__attr,
void * (*__start_routine) (void *), void *__arg));
最初のパラメータはスレッド識別子へのポインタ、2 番目のパラメータはスレッド属性の設定に使用され、3 番目のパラメータはスレッドの開始位置です。スレッド実行関数。開始アドレス、最後のパラメータは関数を実行するためのパラメータです。ここで、関数スレッドはパラメーターを必要としないため、最後のパラメーターは null ポインターに設定されます。また、2 番目のパラメーターを null ポインターに設定します。これにより、デフォルトの属性を持つスレッドが生成されます。スレッド属性の設定と変更については次のセクションで説明します。スレッドが正常に作成された場合、関数は 0 を返します。0 でない場合、スレッドの作成は失敗します。一般的なエラーの戻りコードは eagain と einval です。前者は、スレッドの数が多すぎるなど、システムが新しいスレッドの作成を制限していることを意味し、後者は、2 番目のパラメータで表されるスレッド属性値が不正であることを意味します。スレッドが正常に作成されると、新しく作成されたスレッドはパラメーター 3 とパラメーター 4 で決定された関数を実行し、元のスレッドはコードの次の行の実行を続けます。
3 つの pthread_join pthread_exit
関数 pthread_join は、スレッドの終了を待つために使用されます。関数のプロトタイプは次のとおりです:
extern int pthread_join __p ((pthread_t __th, void **__thread_return));
最初のパラメータは待機するスレッド識別子で、2 番目のパラメータはユーザー定義のポインタです。待機中のスレッドの戻り値を格納するために使用できます。この関数はスレッドブロック関数です。この関数を呼び出した関数は、待機中のスレッドが終了するまで待機します。関数が復帰すると、待機中のスレッドのリソースが回復されます。スレッドを終了するには 2 つの方法があります。1 つは上の例と同様です。関数が終了すると、その関数を呼び出したスレッドも終了します。もう 1 つは、関数 pthread_exit を使用する方法です。その関数プロトタイプは次のとおりです。
extern void pthread_exit __p ((void *__retval)) __attribute__ ((__noreturn__));
pthread_join の 2 番目のパラメーター thread_return が次のとおりである限り、唯一のパラメーターは関数の戻りコードです。 null ではない場合、この値は thread_return に渡されます。最後に注意すべきことは、1 つのスレッドを複数のスレッドで待機させることはできないということです。そうでない場合は、シグナルを受信した最初のスレッドが正常に戻り、pthread_join を呼び出す残りのスレッドはエラー コード esrch を返します。
このセクションでは、最も単純なスレッドを作成し、最もよく使用される 3 つの関数 pthread_create、pthread_join、および pthread_exit を習得しました。次に、スレッドのいくつかの一般的なプロパティとその設定方法を見てみましょう。
ミューテックス ロック関連
ミューテックス ロックは、一定期間内に 1 つのスレッドだけがコードを実行することを保証するために使用されます。
1pthread_mutex_init
関数 pthread_mutex_init は、ミューテックス ロックを生成するために使用されます。 null パラメータは、デフォルトのプロパティが使用されることを示します。特定の属性のミューテックスを宣言する必要がある場合は、関数 pthread_mutexattr_init を呼び出す必要があります。関数 pthread_mutexattr_setpshared および関数 pthread_mutexattr_settype は、ミューテックス ロック属性を設定するために使用されます。前の関数は、pthread_process_private と pthread_process_shared という 2 つの値を持つ属性 pshared を設定します。前者は異なるプロセスのスレッドを同期するために使用され、後者はこのプロセスの異なるスレッドを同期するために使用されます。上の例では、デフォルトの属性 pthread_process_private を使用しています。後者はミューテックス ロック タイプの設定に使用され、オプションのタイプは pthread_mutex_normal、pthread_mutex_errorcheck、pthread_mutex_recursive、および pthread _mutex_default です。これらはそれぞれ異なるリストおよびロック解除メカニズムを定義しており、通常の状況では、最後のデフォルト属性が選択されます。
2 pthread_mutex_lock pthread_mutex_unlock pthread_lay_np
pthread_mutex_lock ステートメントは、ミューテックス ロックでロックを開始します。後続のコードは、pthread_mutex_unlock が呼び出されるまでロックされます。つまり、このコードは 1 つのスレッドによってのみ呼び出され、実行されます。同時に。スレッドが pthread_mutex_lock を実行するときに、その時点でロックが別のスレッドによって使用されている場合、スレッドはブロックされます。つまり、プログラムは別のスレッドがミューテックス ロックを解放するまで待機します。 ######知らせ:###
1 上記の 2 つのスリープはデモのためだけではなく、スレッドを一定期間スリープさせて、スレッドがミューテックス ロックを解放し、別のスレッドがこのロックを使用するのを待機できるようにするためのものであることに注意してください。 。この問題については、以下の参考文献 1 で説明されています。ただし、Linux には pthread_lay_np 関数がないようなので(試してみたところ、定義された関数への参照がありませんと表示されました)、代わりに sleep を使用しましたが、参考 2 には別の方法が記載されているようです。これは、それを実現する方法を提供する pthread_cond_timedwait. に置き換えられます。
2 中のコメント 1 ~ 5 に注目してください。問題を見つけるのに数時間かかった箇所です。
comment1、comment4、comment5 がない場合、pthread_join 時にセグメンテーション違反が発生します また、上記の comment2 と comment3 が根本原因となるため、コード全体を忘れずに記述してください。上記スレッドが正常に作成されていない可能性があるため、そのスレッドの終了を待つことができず、pthread_joinを使用するとセグメンテーションフォルト(不明なメモリ領域にアクセスされる)が発生します。さらに、memset を使用する場合は、string.h ヘッダー ファイルをインクルードする必要があります
以上がLinux マルチスレッド プログラミングのサンプル コード分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。