pthread_create -
新しいスレッドを作成する
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
-pthread
を付けてコンパイルとリンクを行う。
pthread_create()
関数は、呼び出したプロセス内に新しいスレッドを作成する。
新しいスレッドの実行は、
start_routine()
を起動することで開始される。
start_routine()
は引数を一つだけ取り、
arg が
start_routine()
の引数として渡される。
新しく作成されたスレッドは、以下のいずれかで終了する。
- *
- スレッドが
pthread_exit(3) を呼び出す。
pthread_exit(3)
を呼び出す際には終了ステータス値を指定する。
この値は pthread_join(3)
を呼び出した同じプロセス内の
別のスレッドで参照できる。
- *
- スレッドが
start_routine()
から返る。これは、
return 文に渡した値で
pthread_exit(3)
を呼び出すのと等価である。
- *
- スレッドがキャンセルされる
( pthread_cancel(3) 参照)。
- *
- プロセス内のいずれかのスレッドで
exit(3) が呼ばれるか、
メインスレッドで
main() 内で return
が実行される。
この場合は、プロセス内の全てのスレッドが終了される。
attr 引数は
pthread_attr_t
構造体へのポインターであり、
pthread_attr_t
構造体の内容を使用して、スレッド作成時に
新しいスレッドの属性が決定される。
この構造体は
pthread_attr_init(3)
や関連の関数を使って初期化される。
attr が NULL
の場合、新しいスレッドはデフォルトの属性で作成される。
成功した場合は、
pthread_create()
は返る前に新しいスレッドの
ID を
thread
が指すバッファーに格納する。この
ID は、これ以降に他の
pthreads
関数の呼び出しでスレッドを参照するのに使用される。
新しいスレッドは、スレッドを作成したスレッドのシグナルマスク
(
pthread_sigmask(3) 参照)
のコピーを継承する。
新しいスレッドの処理待ちシグナル
(
sigpending(2))
の集合は空となる。
新しいスレッドはスレッドを作成したスレッドの代替シグナルスタック
(
sigaltstack(2))
を継承しない。
新しいスレッドは呼び出したスレッドの浮動小数点環境
(
fenv(3)) を継承する。
新しいスレッドの CPU
時間時計の初期値は 0
である (
pthread_getcpuclockid(3)
参照)。
新しいスレッドは、呼び出したスレッドの
ケーパビリティセット
(
capabilities(7) 参照) と CPU affinity
マスク (
sched_setaffinity(2) 参照)
の
コピーをを継承しない。
成功すると、
pthread_create()
は 0 を返す。
エラーの場合は、エラー番号が返され、
*thread
の内容は不定である。
- EAGAIN
- 別のスレッドを作成するのに十分なリソースがない。
- EAGAIN
- システムで設定されたスレッド数の上限に達していた。
このエラーの原因となる上限値はいくつかある。
実ユーザー ID
当たりのプロセス数とスレッド数の上限である、ソフトリソース上限
RLIMIT_NPROC に達していた
(setrlimit(2)
で設定できる)。
カーネルのシステム全体のプロセスとスレッドの数の上限値である
/proc/sys/kernel/threads-max
が達していた ( proc(5)
参照)。 PID の最大値
/proc/sys/kernel/pid_max
に達していた ( proc(5)
参照)。
- EINVAL
-
attr
で指定された設定が不正である。
- EPERM
-
attr
に指定されたスケジューリングポリシーとパラメーターを
設定する許可がない。
この節で使用されている用語の説明については、
attributes(7) を参照。
インターフェース |
属性 |
値 |
pthread_create() |
Thread safety |
MT-Safe |
POSIX.1-2001, POSIX.1-2008.
pthread_create() が
*thread
で返すスレッド ID
についての
詳しい情報は
pthread_self(3)
を参照のこと。
リアルタイムスケジューリングポリシーが使用されない限り、
pthread_create()
の呼び出し後に、
どのスレッドが—呼び出したスレッドか新しいスレッドか—
次に実行されるかは決まっていない。
スレッドは
join 可能か
detached
(切り離された状態)
のどちらかに
することができる。スレッドが
join
可能な場合、別のスレッドが
pthread_join(3)
を使って終了したスレッドを待ち、終了ステータスを取得
することができる。終了した
join 可能なスレッドは join
された場合にのみ、
そのスレッドの最後に残ったリソースが解放されシステムに戻される。
detached
状態のスレッドが終了すると、そのスレッドのリソースは自動的に
システムに戻される。detached
状態のスレッドを join
して、その終了
ステータスを取得することはできない。スレッドを
detached 状態にするのは、
その終了ステータスをアプリケーションが気にする必要がないある種の
デーモン (daemon)
スレッドでは有用である。
デフォルトでは、新しいスレッドは
join
可能な状態で作成される。
(
pthread_attr_setdetachstate(3) を使って)
attr でスレッドが detached
状態で作成されるように設定されていない限り、join
可能な状態で
作成される。
Under the NPTL threading implementation, if the
RLIMIT_STACK soft
resource limit
at the time the program started has any value other than
"unlimited", then it determines the default stack size of new
threads. Using
pthread_attr_setstacksize(3), the stack size attribute
can be explicitly set in the
attr argument used to create a thread, in
order to obtain a stack size other than the default. If the
RLIMIT_STACK resource limit is set to "unlimited", a
per-architecture value is used for the stack size. Here is the value for a few
architectures:
Architecture |
Default stack size |
i386 |
2 MB |
IA-64 |
32 MB |
PowerPC |
4 MB |
S/390 |
2 MB |
Sparc-32 |
2 MB |
Sparc-64 |
4 MB |
x86_64 |
2 MB |
廃止予定の LinuxThreads
実装では、プロセス内の各スレッドは異なる
プロセス ID
を持つ。これは POSIX
スレッドの規格に違反しており、
他の多くの標準非準拠の点の原因になっている。
pthreads(7) を参照のこと。
以下のプログラムは、
pthread_create() や pthreads API
の他のいろいろな関数の使用例を示している。
以下の実行例は、 NPTL
スレッド実装が提供されているシステムでのもので、
スタックサイズがデフォルト値の
"stack size"
リソース上限で指定される値
になる。
$ ulimit -s
8192 # The stack size limit is 8 MB (0x800000 bytes)
$ ./a.out hola salut servus
Thread 1: top of stack near 0xb7dd03b8; argv_string=hola
Thread 2: top of stack near 0xb75cf3b8; argv_string=salut
Thread 3: top of stack near 0xb6dce3b8; argv_string=servus
Joined with thread 1; returned value was HOLA
Joined with thread 2; returned value was SALUT
Joined with thread 3; returned value was SERVUS
次の実行例では、プログラム内で、作成されるスレッドに対して
(
pthread_attr_setstacksize(3)
を使って1 MB
のスタックサイズを明示的に設定している。
$ ./a.out -s 0x100000 hola salut servus
Thread 1: top of stack near 0xb7d723b8; argv_string=hola
Thread 2: top of stack near 0xb7c713b8; argv_string=salut
Thread 3: top of stack near 0xb7b703b8; argv_string=servus
Joined with thread 1; returned value was HOLA
Joined with thread 2; returned value was SALUT
Joined with thread 3; returned value was SERVUS
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct thread_info { /* Used as argument to thread_start() */
pthread_t thread_id; /* ID returned by pthread_create() */
int thread_num; /* Application-defined thread # */
char *argv_string; /* From command-line argument */
};
/* Thread start function: display address near top of our stack,
and return upper-cased copy of argv_string */
static void *
thread_start(void *arg)
{
struct thread_info *tinfo = arg;
char *uargv;
printf("Thread %d: top of stack near %p; argv_string=%s\n",
tinfo->thread_num, &p, tinfo->argv_string);
uargv = strdup(tinfo->argv_string);
if (uargv == NULL)
handle_error("strdup");
for (char *p = uargv; *p != '\0'; p++)
*p = toupper(*p);
return uargv;
}
int
main(int argc, char *argv[])
{
int s, opt, num_threads;
pthread_attr_t attr;
size_t stack_size;
void *res;
/* The "-s" option specifies a stack size for our threads */
stack_size = -1;
while ((opt = getopt(argc, argv, "s:")) != -1) {
switch (opt) {
case 's':
stack_size = strtoul(optarg, NULL, 0);
break;
default:
fprintf(stderr, "Usage: %s [-s stack-size] arg...\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
num_threads = argc - optind;
/* Initialize thread creation attributes */
s = pthread_attr_init(&attr);
if (s != 0)
handle_error_en(s, "pthread_attr_init");
if (stack_size > 0) {
s = pthread_attr_setstacksize(&attr, stack_size);
if (s != 0)
handle_error_en(s, "pthread_attr_setstacksize");
}
/* Allocate memory for pthread_create() arguments */
struct thread_info *tinfo = calloc(num_threads, sizeof(*tinfo));
if (tinfo == NULL)
handle_error("calloc");
/* Create one thread for each command-line argument */
for (int tnum = 0; tnum < num_threads; tnum++) {
tinfo[tnum].thread_num = tnum + 1;
tinfo[tnum].argv_string = argv[optind + tnum];
/* The pthread_create() call stores the thread ID into
corresponding element of tinfo[] */
s = pthread_create(&tinfo[tnum].thread_id, &attr,
&thread_start, &tinfo[tnum]);
if (s != 0)
handle_error_en(s, "pthread_create");
}
/* Destroy the thread attributes object, since it is no
longer needed */
s = pthread_attr_destroy(&attr);
if (s != 0)
handle_error_en(s, "pthread_attr_destroy");
/* Now join with each thread, and display its returned value */
for (int tnum = 0; tnum < num_threads; tnum++) {
s = pthread_join(tinfo[tnum].thread_id, &res);
if (s != 0)
handle_error_en(s, "pthread_join");
printf("Joined with thread %d; returned value was %s\n",
tinfo[tnum].thread_num, (char *) res);
free(res); /* Free memory allocated by thread */
}
free(tinfo);
exit(EXIT_SUCCESS);
}
getrlimit(2),
pthread_attr_init(3),
pthread_cancel(3),
pthread_detach(3),
pthread_equal(3),
pthread_exit(3),
pthread_getattr_np(3),
pthread_join(3),
pthread_self(3),
pthread_setattr_default_np(3),
pthreads(7)
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。