マルチスレッド・プログラムの開発

マルチスレッド・プログラムの開発は、複数プロセスのプログラムの開発とほぼ同じです。プログラムの開発は、コードのコンパイルおよびデバッグからなります。

マルチスレッド・プログラムのコンパイル

この項では、マルチスレッド・プログラムの生成方法について説明します。説明する項目は、次のとおりです。
  • 必須のヘッダー・ファイル
  • マルチスレッド・プログラムの生成に使用されるコンパイラーの起動

ヘッダー・ファイル

スレッド・ライブラリーを使用するためのすべてのサブルーチン・プロトタイプ、マクロ、およびその他の定義は、/usr/include ディレクトリーに置かれている pthread.h ヘッダー・ファイル内にあります。 pthread.h ヘッダー・ファイルは、スレッド・ライブラリーを使用する各ソース・ファイルに組み込まれている必要があります。

pthread.h ヘッダーには、次のグローバル定義を提供する unistd.h ヘッダーが組み込まれています。

_POSIX_REENTRANT_FUNCTIONS
すべての関数が再入可能でなければならないことを指定します。 複数のヘッダー・ファイルがこのシンボルを使用して、 localtime_r サブルーチンなどの補足再入可能サブルーチンを定義します。
_POSIX_THREADS
POSIX スレッド API を示します。 このシンボルは、POSIX スレッド API が使用可能かどうかのチェックに使用されます。 マクロやサブルーチンは、POSIX または他のいくつかのスレッド API を使用するか否かによって、 さまざまな方法で定義することができます。

pthread.h ファイルには errno.h も組み込まれています。そのファイルで、errno グローバル変数はスレッド固有に再定義されています。 したがって、errno ID は、マルチスレッド・プログラムの左辺値ではなくなります。

コンパイラーの起動

マルチスレッド・プログラムのコンパイル時には、以下のコマンドのいずれかを使用して、C コンパイラーを起動します。
xlc_r
ansi のデフォルト言語レベルでコンパイラーを起動します。
cc_r
extended のデフォルト言語レベルでコンパイラーを起動します。

これらのコマンドによって、Single UNIX Specification, Version 2 に準拠するように、 適切なオプションとライブラリーを使用することができます。 POSIX スレッド仕様 1003.1c は、Single UNIX Specification, Version 2 のサブセットです。

以下のライブラリーは、 xlc_r および cc_r コマンドを使用すると自動的にユーザーのプログラムにリンクされます。
libpthreads.a
スレッド・ライブラリー
libc.a
標準 C ライブラリー
例えば、以下のコマンドは、foo.c マルチスレッド C ソース・ファイルをコンパイルして、foo 実行可能ファイルを作成します。

cc_r -o foo foo.c

POSIX 1003.1c のドラフト 7 用コンパイラーの起動

AIX® では、ドラフト 7 アプリケーションのソース・コードに互換性があります。 開発者は、スレッド化アプリケーションを、 最新の標準システムに移植することをお勧めします。

マルチスレッド・プログラムをドラフト 7 のスレッドのサポート用にコンパイルするときは、以下のコマンドの中の 1 つを使用して C コンパイラーを呼び出します。
xlc_r7
ansi のデフォルト言語レベルでコンパイラーを起動します。
cc_r7
extended のデフォルト言語レベルでコンパイラーを起動します。
以下のライブラリーは、 xlc_r7 および cc_r7 コマンドを使用すると自動的にユーザーのプログラムにリンクされます。
libpthreads_compat.a
ドラフト 7 互換スレッド・ライブラリー
libpthreads.a
スレッド・ライブラリー
libc.a
標準 C ライブラリー

ソース・コード互換性を実現するには、コンパイラー指示 _AIX_PTHREADS_D7 を使用します。 さらに、ライブラリーを libpthreads_compat.alibpthreads.a、そして libc.a の順序でリンクする必要があります。 大部分のユーザーは、この情報を知っている必要はありません。 上記のコマンドが必要なオプションを提供するからです。 これらのオプションは、最新の AIX コンパイラーを持っていないユーザーのために用意されています。

&Symbol.unixspec; へのドラフト 7 アプリケーションの移植

ドラフト 7 と最終標準との相違点は、次のとおりです。
  • errno についてのわずかな相違。 最も一般的なものは、ESRCH を使用しても、 指定された pthread が見つからないことがあるということです。 ドラフト 7 では、この障害による EINVAL が頻繁に戻されます。
  • pthread の作成時のデフォルトの状態は、結合可能 です。 これは、無視されるとメモリー・リークになる可能性があるので、重大な変更です。
  • デフォルトの pthread スケジューリング・パラメーターは 有効範囲 です。
  • pthread_yield サブルーチンは、sched_yield サブルーチンに置き換えられました。
  • 相互排除ロックに関連したさまざまなスケジューリング・ポリシーが多少異なります。

マルチスレッド・プログラムのメモリー所要量

AIX は、単一プロセス内で最大 32768 までのスレッドをサポートします。 個々の pthread は、 プロセスが持つことができる pthread の実際の最大数がメモリー・モデルと他の目的のプロセス・アドレス・スペースの使用によって決まるので、 多少のプロセス・アドレス・スペースを必要とします。 pthread が必要とするメモリーの量は、 スタック・サイズと保護領域サイズに内部使用のための多少の量を加えたもので構成されます。 ユーザーは、pthread_attr_setstacksize サブルーチンでスタックのサイズを制御し、pthread_attr_setguardsize サブルーチンで保護領域のサイズを制御できます。
注: コマンド ulimit -s で規定されているスタック・サイズに対するソフト制限は、 アプリケーションのメイン・スレッドのスタックに対してのみ適用されます。
次の表は、NULL pthread 属性を使用してループで pthread を作成するだけの簡単なプログラムを使用して、32 ビット・プロセス内で作成可能な pthread の最大数を示しています。 実際のプログラムにおける実際の数は、 プログラムにおける他のメモリーの使用量によって決まります。 64 ビット・プロセスの場合、ulimit サブルーチンが、作成されるスレッド数を制御します。 したがって、大きいデータ・モデルは必要なく、実際にスレッドの最大数を減らすことができます。
データ・モデル -bmaxdata 最大 Pthread 数
小さいデータ 適用不能 1084
大きいデータ 0x10000000 2169
大きいデータ 0x20000000 4340
大きいデータ 0x30000000 6510
大きいデータ 0x40000000 8681
大きいデータ 0x50000000 10852
大きいデータ 0x60000000 13022
大きいデータ 0x70000000 15193
大きいデータ 0x80000000 17364
NUM_SPAREVP 環境 変数は、ライブラリーにより維持される予備の仮想プロセッサーの数を制御するのに設定することができます。 この 変数は、必ずしも変更する必要はありません。 ある状況では、2、3 メガバイトのメモリーのみを使用する アプリケーションは、NUM_SPAREVP 環境変数を小さい値に設定することにより メモリー・オーバーヘッドを削減できます。 典型的な設定値には、システムの CPU の数またはプロセス・スレッドのピークの数が示されます。 この変数の設定値は、プロセスのパフォーマンスに影響を与えません。 デフォルトの設定値は、256 です。
注: NUM_SPAREVP 環境変数は、AIX 5.1 でのみ使用可能です。

マルチスレッド・プログラムの例

次の簡単なマルチスレッド・プログラムでは、"Hello!" という語を英語とフランス語の両方で 5 秒間表示します。cc_r または xlc_r でコンパイルしてください。 F
#include <pthread.h>    /* include file for pthreads - the 1st */
#include <stdio.h>      /* include file for printf()           */
#include <unistd.h>     /* include file for sleep()            */

void *Thread(void *string)
{
        while (1)
                printf("%s¥n", (char *)string);
        pthread_exit(NULL);
}

int main()
{
        char *e_str = "Hello!";
        char *f_str = "Bonjour !";

        pthread_t e_th;
        pthread_t f_th;

        int rc;

        rc = pthread_create(&e_th, NULL, Thread, (void *)e_str);
        if (rc)
                exit(-1);
        rc = pthread_create(&f_th, NULL, Thread, (void *)f_str);
        if (rc)
                exit(-1);
        sleep(5);

        /* usually the exit subroutine should not be used
           see below to get more information */
        exit(0);
}

初期スレッド (main ルーチンを実行している) は、2 つのスレッドを作成します。 両方のスレッドとも、 同じエントリー・ポイント・ルーチン (Thread ルーチン) を持っていますが、 パラメーターは異なります。 このパラメーターは、表示される文字列を指すポインターです。

マルチスレッド・プログラムのデバッグ

次のツールは、マルチスレッド・プログラムのデバッグに使用することができます。
  • アプリケーション・プログラマーは、 dbx コマンドを使用してデバッグを実行することができます。 スレッド関連のオブジェクトを表示するために、複数のサブコマンド (attributeconditionmutex、および thread) が使用可能です。
  • カーネル・プログラマーは、カーネル・デバッグ・プログラムを使用して、 カーネル・エクステンションとデバイス・ドライバーのデバッグを実行することができます。 カーネル・デバッグ・プログラムは、 ユーザー・スレッドへのアクセスを制限し、 主にカーネル・スレッドの操作を行います。 次のものを含めて、いくつかのサブコマンドが複数のカーネル・スレッドとプロセッサーをサポートします。
    • cpu サブコマンド。現行のプロセッサーを変更します。
    • ppd サブコマンド。プロセッサーごとのデータ構造を表示します。
    • thread サブコマンド。スレッド・テーブル項目を表示します。
    • uthread サブコマンド。スレッドの uthread 構造を表示します。
    カーネル・デバッグ・プログラムの詳細については、「Kernel Extensions and Device Support Programming Concepts」を参照してください。

マルチスレッド・プログラムのコア・ファイル要件

デフォルトでは、プロセスはフル・コア・ファイルを生成しません。 アプリケーションが共用メモリー領域 (特にスレッド・スタック) 内のデータをデバッグする必要がある場合、フル・コア・ダンプを生成する必要があります。 フル・コア・ファイル情報を生成するには、 以下のコマンドを root ユーザーとして実行してください。
	chdev -l sys0 -a fullcore=true

それぞれの pthread が、生成されたコア・ファイルのサイズに追加されます。 pthread に必要なコア・ファイル・スペースの量には、ユーザーが pthread_attr_setstacksize サブルーチンによって制御できるスタック・サイズが含まれます。 NULL の pthread 属性で作成された pthread の場合、 32 ビット・プロセス内の各 pthread は、 コア・ファイルのサイズに 128 KB を追加し、 64 ビット・プロセス内の各 pthread はコア・ファイルのサイズに 256 KB を追加します。