マルチスレッドのプログラミング

pthread に相当するものがある Solaris スレッドの関数

操作 

参照先 

スレッドの生成 

「thr_create(3THR)」

最小のスタックの大きさの取得 

「thr_min_stack(3THR)」

スレッド識別子の取得 

「thr_self(3THR)」

スレッドの実行明け渡し 

「thr_yield(3THR)」

シグナルのスレッドへの送信 

「thr_kill(3THR)」

呼び出しスレッドのシグナルマスクのアクセス 

「thr_sigsetmask(3THR)」

スレッドの終了 

「thr_exit(3THR)」

スレッドの終了待ち 

「thr_join(3THR)」

スレッド固有データ用キーの作成 

「thr_keycreate(3THR)」

スレッド固有データ用キーの設定 

「thr_setspecific(3THR)」

スレッド固有データ用キーの取得 

「thr_getspecific(3THR)」

スレッド優先順位の設定 

「thr_setprio(3THR)」

スレッド優先順位の取得 

「thr_getprio(3THR)」

スレッドの生成

thr_create(3THR) は、Solaris スレッドライブラリルーチンの中で最も精巧なルーチンの 1 つです。

thr_create(3THR)

thr_create(3THR) は、現在のプロセスに新しい制御スレッドを追加します。(POSIX スレッドについては、「pthread_create(3THR) 」を参照)。

新しいスレッドは保留状態のシグナルは継承しませんが、優先順位とシグナルマスクを継承することに注意してください。


#include <thread.h>

int thr_create(void *stack_base, size_t stack_size,
    void *(*start_routine) (void *), void *arg, long flags,
    thread_t *new_thread);

size_t thr_min_stack(void);

stack_base - 新しいスレッドが使用するスタックのアドレスを指定します。NULL を指定すると、新しいスレッドに stack_size バイト以上の大きさをもつスタックが割り当てられます。

stack_size - 新しいスレッドが使用するスタックのバイト数を指定します。0 を指定するとデフォルト値が使用されます。通常は 0 を指定してください。それ以外の値を指定する場合は、thr_min_stack() で戻された値よりも大きな値を指定してください。

通常は、スレッドのためのスタック空間を割り当てる必要はありません。スレッドライブラリが、各スレッドのスタック用に 1M バイトの仮想記憶をスワップ空間の予約なしで割り当てます。(スレッドライブラリは、mmap(2)MAP_NORESERVE オプションを使って割り当てます。)

start_routine - 新しいスレッドで実行する関数を指定します。start_routine() で指定した関数が終了すると、スレッドはその関数の戻り値を終了状態に設定して終了します (詳細は、「thr_exit(3THR)」を参照) してください。

arg - void で記述される任意のもの。通常は 4 バイト値です。それよりも大きな値は、そのポインタを引数とすることによって間接的に渡さなければなりません。

引数は 1 つしか指定できません。複数の引数を与えるためには、それらを 1 つのものとして (構造体に入れるなどの方法で) コーディングしてください。

flags - 生成されるスレッドの属性を指定します。通常は 0 を指定します。

flags の値は、以下に示すフラグのビット単位の論理和となります。


注 -

明示的な同期によって阻止されなければ、停止していない切り離されたスレッドは、そのスレッドの生成元が thr_create() から復帰する前に終了でき、そのスレッド識別子は別の新しいスレッドに割り当てることができます。


new_thread - NULL 以外を指定すると、new_thread の指すアドレスに新しいスレッドのスレッド識別子が格納されます。この引数が指す記憶領域は、呼び出し側の責任で確保しなければなりません。このスレッド識別子は、呼び出し側のプロセス内でだけ有効です。

スレッド識別子が特に必要でなければ、new_thread に 0 を指定してください。

戻り値

正常終了時は 0 です。それ以外の戻り値は、エラーが発生したことを示します。以下のいずれかの条件が検出されると、thr_create() は失敗し、対応する値を戻します。


EAGAIN

システム制限を超えました。たとえば、生成された LWP が多すぎます。


ENOMEM

新しいスレッドを生成するための十分なメモリーがありません。


EINVAL

stack_base が NULL でなく、しかも stack_sizethr_min_stack() の戻り値より小さな値を指定しました。

スタックの動作

Solaris スレッドでのスタックの動作は、通常は pthread の場合と同じです。スタックの設定と操作の詳細は、「スタックについて」を参照してください。

thr_min_stack() を呼び出すと、スタックの大きさの絶対最小値が得られます。この関数は、NULL 手続きを実行するスレッドに必要なスタック空間の大きさを戻します。実用的なスレッドに必要なスタック空間はもっと大きいので、スタックの大きさを小さくするときは十分注意してください。

独自のスタックを指定する方法は 2 通りあります。1 つは、thr_create() でスタックアドレスを NULL に指定し、スタック空間の割り当てをスレッドライブラリに任せる方法です。スタックの大きさを指定するパラメタには、希望の大きさを指定します。

もう 1 つの方法は、thr_create() でスタックアドレスを指定して、スタックをすべて自分で管理する方法です。この場合は、スタック空間の割り当てだけでなく解放もユーザ自身で行う必要があります。つまり、スレッドの終了時にスタックを処分しなければなりません。

独自のスタックを割り当てる場合は、mprotect(2) を呼び出して、スタックの最後に必ずレッドゾーンを付加してください。

最小のスタックの大きさの取得

thr_min_stack(3THR)

thr_min_stack(3THR) は、スレッドの最小のスタックの大きさを取得します。


#include <thread.h>

size_t thr_min_stack(void);

NULL スレッドを実行するために必要なスタック空間の大きさが戻されます (NULL スレッドとは、中身のない (NULL) 手続きを実行するために生成されるスレッドのことです)。

スレッドが NULL 手続きでなく通常の手続きを実行する場合は、thr_min_stack() の戻り値よりも大きなスタックの大きさを割り当てなければなりません。

スレッドの生成時に、ユーザが独自のスタックを指定する場合は、そのスレッドを実行するために十分な大きさのスタック空間を、ユーザ自身が確保しなければなりません。動的にリンクされるような実行環境では、スレッドのスタックの大きさの最小限必要な量を見積もることは困難です。

通常、ユーザ独自のスタックが必要になることはまれです。実際、アプリケーション側が実行環境を完全に制御するなどのごく限られた状況でしか必要になりません。

ユーザは、スレッドライブラリにスタックの割り当てを任せることができます。スレッドライブラリのデフォルトのスタックは、すべてのスレッドの要求を満たします。

スレッド識別子の取得

thr_self(3THR)

thr_self(3THR) は、呼び出しスレッドの識別子を取得します。(POSIX スレッドについては、「pthread_self(3THR)」を参照)。


#include <thread.h>

thread_t thr_self(void);

スレッドの実行明け渡し

thr_yield(3THR)

thr_yield(3THR) は、現在のスレッドから同じ優先順位か、より高い優先順位をもつ別のスレッドに実行権を譲ります。それ以外は何の効果もありません。thr_yield() の呼び出しスレッドがそうするという保証はありません。


#include <thread.h>

void thr_yield(void);

シグナルのスレッドへの送信

thr_kill(3THR)

thr_kill(3THR) は、スレッドにシグナルを送ります。(POSIX スレッドについては、「pthread_kill(3THR)」を参照)。


#include <thread.h>
#include <signal.h>
int thr_kill(thread_t target_thread, int sig);

呼び出しスレッドのシグナルマスクのアクセス

thr_sigsetmask(3THR)

thr_sigsetmask(3THR) は、呼び出しスレッドのシグナルマスクの変更や照会を行います。


#include <thread.h>
#include <signal.h>
int thr_sigsetmask(int how, const sigset_t *set, sigset_t *oset);

スレッドの終了

thr_exit(3THR)

thr_exit(3THR) はスレッドを終了させます。(POSIX スレッドについては、「pthread_exit(3THR)」を参照)。


#include <thread.h>

void thr_exit(void *status);

スレッドの終了待ち

thr_join(3THR)

thr_join(3THR) 関数はスレッドの終了を待ちます。(POSIX スレッドについては、「pthread_join(3THR)」を参照)。


#include <thread.h>

int thr_join(thread_t tid, thread_t *departedid, void **status);

指定したスレッドの終了待ち


#include <thread.h>

thread_t tid;
thread_t departedid;
int ret;
int status;

/* スレッド「tid」の終了待ち、status の指定あり */
ret = thr_join(tid, &departedid, (void**)&status);

/* スレッド「tid」の終了待ち、status の指定なし */
ret = thr_join(tid, &departedid, NULL);

/* スレッド「tid」の終了待ち、departedid と status の指定なし */
ret = thr_join(tid, NULL, NULL); 

tid(thread_t) 0 の場合は、thr_join() はプロセス内の切り離されていない任意のスレッドの終了を待ちます。つまり、スレッド識別子を指定しなければ、切り離されていないスレッドのどれかが終了すると thr_join() が復帰します。

任意のスレッドの終了待ち


#include <thread.h>

thread_t tid;
thread_t departedid;
int ret;
int status;

/* スレッド「tid」の終了待ち、status の指定あり */
ret = thr_join(NULL, &departedid, (void **)&status); 

thr_join() でスレッド識別子として NULL を指定すると、プロセス内の切り離されていない任意のスレッドの終了を待ちます。departedid には、終了したスレッドのスレッド識別子が格納されます。

スレッド固有データ用キーの作成

関数名と引数を別にすれば、スレッド固有データは Solaris のものも POSIX のものも同じです。この節では、Solaris の関数の概要を説明します。

thr_keycreate(3THR)

thr_keycreate(3THR) は、プロセス内のスレッド固有データを識別するためのキーを割り当てます。(POSIX スレッドについては、「pthread_key_create(3THR)」を参照)。


#include <thread.h>

int thr_keycreate(thread_key_t *keyp,
    void (*destructor) (void *value));

スレッド固有データ用キーの設定

thr_setspecific(3THR)

thr_setspecific(3THR) は、呼び出しスレッドで、値 (value) とスレッド固有データのキー (key) を結び付けます。(POSIX スレッドについては、「pthread_setspecific(3THR)」を参照)。


#include <thread.h>

int thr_setspecific(thread_key_t key, void *value);

スレッド固有データ用キーの取得

thr_getspecific(3THR)

thr_getspecific(3THR) は、key で指定したキーに結び付けられている現在の値を、valuep が指している位置に格納します。(POSIX スレッドについては、「pthread_getspecific(3THR)」を参照)。


#include <thread.h>

int thr_getspecific(thread_key_t key, void **valuep);

スレッド優先順位の設定

Solaris スレッドでは、優先順位が親と異なるスレッドを生成する場合、SUSPEND モードで生成します。そして、停止状態のときに thr_setprio(3T) 関数を使ってスレッド優先順位を変更し、実行を再開します。

通常、非結合スレッドのスケジューリングは、プロセス内の他のスレッドとの関係だけを考慮した単純な優先順位に基づいて行われます。その他の調整が行われたり、カーネルが関係したりすることはありません。スレッドの優先順位は通常は同一であり、生成側プロセスの優先順位を継承します。

thr_setprio(3THR)

thr_setprio(3THR) は、現在のプロセス内の tid で指定したスレッドの優先順位を、newprio で指定した優先順位に変更します。(POSIX スレッドについては、「pthread_setschedparam(3THR)」を参照)。


#include <thread.h>

int thr_setprio(thread_t tid, int newprio)

スレッドのスケジューリングは、デフォルトの設定では、最低の優先順位を表す 0 から最大整数までの範囲の固定的な優先順位に基づいて行われます。tid で指定されたスレッドは、自分より優先順位の低いスレッドから実行リソースを横取りし、自分より優先順位の高いスレッドには実行リソースを譲ります。


thread_t tid;
int ret;
int newprio = 20;

/* 停止状態のスレッドを生成する */
ret = thr_create(NULL, NULL, func, arg, THR_SUSPEND, &tid);

/* 停止状態の子スレッドに対して新しい優先順位を設定する */
ret = thr_setprio(tid, newprio);

/* 停止状態の子スレッドを新しい優先順位で開始する */
ret = thr_continue(tid);

スレッド優先順位の取得

thr_getprio(3THR)

thr_getprio(3THR) は、スレッドの現在の優先順位を取得します。各スレッドは生成側の優先順位を継承します。thr_getprio() は、tid で指定されたスレッドの現在の優先順位を、newprio が指している位置に格納します。(POSIX スレッドについては、「pthread_getschedparam(3THR)」を参照)。


#include <thread.h>

int thr_getprio(thread_t tid, int *newprio)