C++でのマルチスレッドプログラミング入門|POSIXスレッドの作成から終了まで
マルチスレッドとは
マルチスレッドはマルチタスクの特殊な形態であり、マルチタスクとは、コンピュータが2つ以上のプログラムを同時に実行できる機能のことです。マルチタスクには、一般的に「プロセスベース」と「スレッドベース」の2種類があります。
プロセスベースのマルチタスクは、複数のプログラムの同時実行を扱います。一方、スレッドベースのマルチタスクは、同一プログラム内の複数の処理単位の同時実行を扱います。
マルチスレッドプログラムは、同時に実行可能な2つ以上の部分から構成されます。この各部分を「スレッド」と呼び、それぞれのスレッドが独立した実行パスを定義します。
なお、C++言語自体にはマルチスレッドアプリケーション向けの組み込みサポートは用意されておらず、この機能はオペレーティングシステムに完全に依存します。
本チュートリアルでは、Linux OSを前提とし、POSIXを利用したマルチスレッドC++プログラムの作成方法を解説します。POSIX Threads(Pthreads)は、FreeBSD、NetBSD、GNU/Linux、Mac OS X、Solarisなど、多くのUnix系POSIXシステムで利用可能なAPIを提供しています。
スレッドの作成
POSIXスレッドを作成するには、次のルーチンを使用します。
#include <pthread.h> pthread_create (thread, attr, start_routine, arg)
pthread_createは新しいスレッドを生成し、実行可能な状態にします。このルーチンは、コード内のどこからでも何度でも呼び出すことができます。各パラメータの詳細は以下のとおりです。
| パラメータ | 説明 |
|---|---|
| thread | サブルーチンが返す、新しいスレッドの一意な識別子(不透明なオブジェクト)。 |
| attr | スレッド属性を設定するための属性オブジェクト。デフォルト値を使用する場合はNULLを指定します。 |
| start_routine | スレッドが作成された後に実行されるC++ルーチン。 |
| arg | start_routineに渡す単一の引数。void型ポインタへのキャストという形式で渡す必要があります。引数を渡さない場合はNULLを指定できます。 |
1つのプロセスが作成できるスレッドの最大数は実装に依存します。作成されたスレッドは互いに対等な関係にあり、さらに別のスレッドを作成することも可能です。スレッド間に暗黙的な階層構造や依存関係は存在しません。
スレッドの終了
POSIXスレッドを終了するには、次のルーチンを使用します。
#include <pthread.h> pthread_exit (status)
pthread_exitは、スレッドを明示的に終了させるために使用します。通常、pthread_exit()は、スレッドが処理を完了し、その存在が不要になった時点で呼び出されます。
main()が生成したスレッドより先に終了する際にpthread_exit()を呼び出した場合、他のスレッドは実行を継続します。pthread_exit()を呼び出さずにmain()が終了した場合は、すべてのスレッドが自動的に終了されます。
サンプルプログラム
以下は、5つのスレッドを生成し、それぞれのスレッドが「Hello World!」メッセージを出力するシンプルな例です。
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void *PrintHello(void *threadid) {
long tid;
tid = (long)threadid;
cout << "Hello World! Thread ID, " << tid << endl;
pthread_exit(NULL);
}
int main () {
pthread_t threads[NUM_THREADS];
int rc;
int i;
for( i = 0; i < NUM_THREADS; i++ ) {
cout << "main() : creating thread, " << i << endl;
rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
}
コンパイルと実行結果
コンパイル時には、-lpthreadオプションを付けてpthreadライブラリをリンクする必要があります。
$gcc test.cpp -lpthread $./a.out main() : creating thread, 0 main() : creating thread, 1 main() : creating thread, 2 main() : creating thread, 3 main() : creating thread, 4 Hello World! Thread ID, 0 Hello World! Thread ID, 1 Hello World! Thread ID, 2 Hello World! Thread ID, 3 Hello World! Thread ID, 4
このように、main()から5つのスレッドが順に作成され、それぞれのスレッドが独立してメッセージを出力していることが確認できます。なお、スレッドの実行順序はOSのスケジューリングに依存するため、実行のたびに順序が入れ替わる場合があります。
-
Javaスレッドの優先度とは?マルチスレッドにおける優先順位の基本と設定方法
Javaスレッドの優先度とはマルチスレッド環境では、スレッドスケジューラが各スレッドの優先度に基づいて、どのスレッドにCPUを割り当てるかを決定します。Javaのスレッドにはあらかじめデフォルトの優先度が割り当てられており、JVM(Java仮想マシン)が自動的に設定するほか、プログラマが明示的に指定することも可能です。スレッドの優先度は、1から10までの整数値(両端を含む)で表されます。優先度に関連する静的変数として、以下の3つが定義されています。MAX_PRIORITY:スレッドに設定できる最大の優先度。デフォルト値は10。NORM_PRIORITY:スレッドの標準的な優先度。デフォルト値は
-
Javaでスレッドを安全に終了する方法|volatileフラグを使った実装例
Javaでは、実行中のスレッドを外部から強制的に即座に停止させる安全な手段は用意されていません。かつて提供されていた Thread.stop() メソッドは、スレッドが保持しているロックやデータの整合性を壊す恐れがあるため、現在では非推奨(deprecated)となっています。 そこで推奨されるのが、volatile 修飾子を付けた boolean 型のフラグを使い、スレッド自身に終了タイミングを判断させる方法です。以下に具体的な実装例を示します。 コード例 public class Main{ static volatile boolean exit = false; pu