Provided by: manpages-ja_0.5.0.0.20210215+dfsg-1_all
名前
pthreads - POSIX スレッド
説明
POSIX.1 は、一般に POSIX スレッドや Pthreads として知られる スレッドプログラミングのイン ターフェース群 (関数、ヘッダーファイル) を規定している。一つのプロセスは複数のスレッドを 持つことができ、 全てのスレッドは同じプログラムを実行する。 これらのスレッドは同じ大域メモ リー (データとヒープ領域) を共有するが、 各スレッドは自分専用のスタック (自動変数) を持 つ。 POSIX.1 はスレッド間でどのような属性を共有するかについても定めている (つまり、これらの属性 はスレッド単位ではなくプロセス全体で共通である): - プロセス ID - 親プロセス ID - プロセスグループ ID とセッション ID - 制御端末 - ユーザー ID とグループ ID - オープンするファイルディスクリプター - レコードのロック (fcntl(3) 参照) - シグナルの配置 - ファイルモード作成マスク (umask(2)) - カレントディレクトリ (chdir(2)) とルートディレクトリ (chroot(2)) - インターバルタイマー (setitimer(2)) と POSIX タイマー (timer_create(2)) - nice 値 (setpriority(2)) - リソース制限 (setrlimit(2)) - CPU 時間 (times(2)) とリソース (getrusage(2)) の消費状況の計測 スタックについても、POSIX.1 はどのような属性が 個々のスレッドで独立に管理されるかを規定し ている: - スレッド ID (pthread_t データ型) - シグナルマスク (pthread_sigmask(3)) - errno 変数 - 代替シグナルスタック (sigaltstack(2)) - リアルタイムスケジューリングのポリシーと優先度 (sched(7)) 以下の Linux 特有の機能もスレッド単位である: - ケーパビリティ (capabilities(7) 参照) - CPU affinity (親和度) (sched_setaffinity(2)) pthreads 関数の返り値 ほとんどの pthreads 関数は成功すると 0 を返し、 失敗した場合エラー番号を返す。 pthreads 関 数は errno をセットしない点に注意すること。 POSIX.1-2001 では、 エラーを返す可能性のある pthreads 関数がエラー EINTR で失敗することは決してないと規定している。 スレッド ID あるプロセス内の各スレッドは (pthread_t 型の) 一意なスレッド識別子を持つ。 この識別子は、 pthread_create(3) の呼び出し元に返される。また、スレッドは自身のスレッド識別子を pthread_self(3) を使って取得できる。 スレッド ID の一意性が保証されるのは、一つのプロセス 内においてのみである。 終了したスレッドが join された後では、スレッド ID は再利用される可 能性がある。 スレッド ID を引き数に取る全てのスレッド関数において、 その ID は呼び出し元と 同じプロセス内の一つのスレッドを参照する。 スレッドセーフな関数 スレッドセーフな関数は、複数のスレッドから同時に呼び出しても安全な (すなわち、同時に呼び出 されたかに関わらず、同じ結果を返す) 関数のことである。 POSIX.1-2001 と POSIX.1-2008では、一部の例外を除き、 標準で規定されている全ての関数がス レッドセーフであることを要求している。 以下の関数が例外である。 asctime() basename() catgets() crypt() ctermid() (NULL でない引き数を渡された場合) ctime() dbm_clearerr() dbm_close() dbm_delete() dbm_error() dbm_fetch() dbm_firstkey() dbm_nextkey() dbm_open() dbm_store() dirname() dlerror() drand48() ecvt() [POSIX.1-2001 のみ (POSIX.1-2008 で削除された)] encrypt() endgrent() endpwent() endutxent() fcvt() [POSIX.1-2001 のみ (POSIX.1-2008 で削除された)] ftw() gcvt() [POSIX.1-2001 のみ (POSIX.1-2008 で削除された)] getc_unlocked() getchar_unlocked() getdate() getenv() getgrent() getgrgid() getgrnam() gethostbyaddr() [POSIX.1-2001 のみ (POSIX.1-2008 で削除された)] gethostbyname() [POSIX.1-2001 のみ (POSIX.1-2008 で削除された)] gethostent() getlogin() getnetbyaddr() getnetbyname() getnetent() getopt() getprotobyname() getprotobynumber() getprotoent() getpwent() getpwnam() getpwuid() getservbyname() getservbyport() getservent() getutxent() getutxid() getutxline() gmtime() hcreate() hdestroy() hsearch() inet_ntoa() l64a() lgamma() lgammaf() lgammal() localeconv() localtime() lrand48() mrand48() nftw() nl_langinfo() ptsname() putc_unlocked() putchar_unlocked() putenv() pututxline() rand() readdir() setenv() setgrent() setkey() setpwent() setutxent() strerror() strsignal() [POSIX.1-2008 で追加された] strtok() system() [POSIX.1-2008 で追加された] tmpnam() (NULL でない引き数を渡された場合) ttyname() unsetenv() wcrtomb() (最後の引き数が NULL の場合) wcsrtombs() (最後の引き数が NULL の場合) wcstombs() wctomb() async-cancel-safe 関数 async-cancel-safe 関数は、 非同期キャンセル機能が有効になっているアプリケーションで 安全に 呼び出すことができる関数のことである (pthread_setcancelstate(3) を参照)。 以下の関数だけが、POSIX.1-2001 と POSIX.1-2008 で async-cancel-safe で なければならないと されている。 pthread_cancel() pthread_setcancelstate() pthread_setcanceltype() 取り消しポイント (cancellation points) POSIX.1 の規定では、特定の関数は取り消しポイントでなければならず、 他の特定の関数は取り消 しポイントであってもよいとされている。 あるスレッドが取り消し可能で、その取り消し種別 (cancelability type) が延期 (deferred) で、そのスレッドに対する取り消し要求が処理待ちの場 合、 取り消しポイントである関数を呼び出した時点で、そのスレッドのキャンセルが 行われる。 POSIX.1-2001 と POSIX.1-2008 の両方、もしくはいずれか一方では、 以下の関数は、取り消しポイ ント (cancellation points) で あることが必須となっている。 accept() aio_suspend() clock_nanosleep() close() connect() creat() fcntl() F_SETLKW fdatasync() fsync() getmsg() getpmsg() lockf() F_LOCK mq_receive() mq_send() mq_timedreceive() mq_timedsend() msgrcv() msgsnd() msync() nanosleep() open() openat() [POSIX.1-2008 で追加された] pause() poll() pread() pselect() pthread_cond_timedwait() pthread_cond_wait() pthread_join() pthread_testcancel() putmsg() putpmsg() pwrite() read() readv() recv() recvfrom() recvmsg() select() sem_timedwait() sem_wait() send() sendmsg() sendto() sigpause() [POSIX.1-2001 only (moves to "may" list in POSIX.1-2008)] sigsuspend() sigtimedwait() sigwait() sigwaitinfo() sleep() system() tcdrain() usleep() [POSIX.1-2001 のみ (POSIX.1-2008 で削除された)] wait() waitid() waitpid() write() writev() POSIX.1-2001 と POSIX.1-2008 の両方、もしくはいずれか一方では、 以下の関数は、取り消しポイ ント (cancellation points) で あってもよいことになっている。 access() asctime() asctime_r() catclose() catgets() catopen() chmod() [POSIX.1-2008 で追加された] chown() [POSIX.1-2008 で追加された] closedir() closelog() ctermid() ctime() ctime_r() dbm_close() dbm_delete() dbm_fetch() dbm_nextkey() dbm_open() dbm_store() dlclose() dlopen() dprintf() [POSIX.1-2008 で追加された] endgrent() endhostent() endnetent() endprotoent() endpwent() endservent() endutxent() faccessat() [POSIX.1-2008 で追加された] fchmod() [POSIX.1-2008 で追加された] fchmodat() [POSIX.1-2008 で追加された] fchown() [POSIX.1-2008 で追加された] fchownat() [POSIX.1-2008 で追加された] fclose() fcntl() (cmd 引き数が何であっても) fflush() fgetc() fgetpos() fgets() fgetwc() fgetws() fmtmsg() fopen() fpathconf() fprintf() fputc() fputs() fputwc() fputws() fread() freopen() fscanf() fseek() fseeko() fsetpos() fstat() fstatat() [POSIX.1-2008 で追加された] ftell() ftello() ftw() futimens() [POSIX.1-2008 で追加された] fwprintf() fwrite() fwscanf() getaddrinfo() getc() getc_unlocked() getchar() getchar_unlocked() getcwd() getdate() getdelim() [POSIX.1-2008 で追加された] getgrent() getgrgid() getgrgid_r() getgrnam() getgrnam_r() gethostbyaddr() [SUSv3 のみ (この関数は POSIX.1-2008 で削除されている)] gethostbyname() [SUSv3 のみ (この関数は POSIX.1-2008 で削除されている)] gethostent() gethostid() gethostname() getline() [POSIX.1-2008 で追加された] getlogin() getlogin_r() getnameinfo() getnetbyaddr() getnetbyname() getnetent() getopt() (opterr が 0 以外の場合) getprotobyname() getprotobynumber() getprotoent() getpwent() getpwnam() getpwnam_r() getpwuid() getpwuid_r() gets() getservbyname() getservbyport() getservent() getutxent() getutxid() getutxline() getwc() getwchar() getwd() [SUSv3 のみ (この関数は POSIX.1-2008 で削除されている)] glob() iconv_close() iconv_open() ioctl() link() linkat() [POSIX.1-2008 で追加された] lio_listio() [POSIX.1-2008 で追加された] localtime() localtime_r() lockf() [POSIX.1-2008 で追加された] lseek() lstat() mkdir() [POSIX.1-2008 で追加された] mkdirat() [POSIX.1-2008 で追加された] mkdtemp() [POSIX.1-2008 で追加された] mkfifo() [POSIX.1-2008 で追加された] mkfifoat() [POSIX.1-2008 で追加された] mknod() [POSIX.1-2008 で追加された] mknodat() [POSIX.1-2008 で追加された] mkstemp() mktime() nftw() opendir() openlog() pathconf() pclose() perror() popen() posix_fadvise() posix_fallocate() posix_madvise() posix_openpt() posix_spawn() posix_spawnp() posix_trace_clear() posix_trace_close() posix_trace_create() posix_trace_create_withlog() posix_trace_eventtypelist_getnext_id() posix_trace_eventtypelist_rewind() posix_trace_flush() posix_trace_get_attr() posix_trace_get_filter() posix_trace_get_status() posix_trace_getnext_event() posix_trace_open() posix_trace_rewind() posix_trace_set_filter() posix_trace_shutdown() posix_trace_timedgetnext_event() posix_typed_mem_open() printf() psiginfo() [POSIX.1-2008 で追加された] psignal() [POSIX.1-2008 で追加された] pthread_rwlock_rdlock() pthread_rwlock_timedrdlock() pthread_rwlock_timedwrlock() pthread_rwlock_wrlock() putc() putc_unlocked() putchar() putchar_unlocked() puts() pututxline() putwc() putwchar() readdir() readdir_r() readlink() [POSIX.1-2008 で追加された] readlinkat() [POSIX.1-2008 で追加された] remove() rename() renameat() [POSIX.1-2008 で追加された] rewind() rewinddir() scandir() [POSIX.1-2008 で追加された] scanf() seekdir() semop() setgrent() sethostent() setnetent() setprotoent() setpwent() setservent() setutxent() sigpause() [POSIX.1-2008 で追加された] stat() strerror() strerror_r() strftime() symlink() symlinkat() [POSIX.1-2008 で追加された] sync() syslog() tmpfile() tmpnam() ttyname() ttyname_r() tzset() ungetc() ungetwc() unlink() unlinkat() [POSIX.1-2008 で追加された] utime() [POSIX.1-2008 で追加された] utimensat() [POSIX.1-2008 で追加された] utimes() [POSIX.1-2008 で追加された] vdprintf() [POSIX.1-2008 で追加された] vfprintf() vfwprintf() vprintf() vwprintf() wcsftime() wordexp() wprintf() wscanf() 実装時に、標準規格で規定されていないその他の関数を取り消しポイント とすることも認められて いる。 特に、停止 (block) する可能性がある非標準の関数を取り消しポイントと する実装はあり 得ることだろう (ファイルを扱う可能性のあるほとんどの関数がこれに含まれる)。 Linux でのコンパイル Linux では、Pthreads API を用いたプログラムは cc -pthread でコンパイルすべきである。 POSIX スレッドの Linux での実装 これまで、2つのスレッドの実装が Linux の GNU C ライブラリにより 提供されてきた。 LinuxThreads 最初の Pthreads の実装。 glibc 2.4 以降は、この実装はもはやサポートされていない。 NPTL (Native POSIX Threads Library) 新しい Pthreads の実装。LinuxThreads と比べると、 NPTL は POSIX.1 の要求仕様への準 拠の度合いが高く、 多数のスレッドを作成した際の性能も高い。 NPTL は glibc 2.3.2 以 降で利用可能である。 NPTL を利用するには Linux 2.6 カーネルに実装されている機能が必 要である。 どちらの実装もいわゆる 1:1 実装、すなわち個々のスレッドが カーネルのスケジューリング実体に マッピングされる。 どちらのスレッドの実装も Linux の clone(2) システムコールを利用してい る。 NPTL では、スレッド同期の基本機構 (mutex や スレッドの join 等) は Linux の futex(2) システムコールを使って実装されている。 LinuxThreads この実装の大きな特徴は以下の通りである: - メインスレッド (最初のスレッド) とプログラムが pthread_create(3) を使って作成したス レッドに加え、 この実装では「管理 (manager)」スレッドが作成される。 管理スレッドはス レッドの作成と終了を取り扱う (このスレッドがうっかり kill されると、問題が起こることが ある)。 - この実装では内部でシグナルを使用している。 Linux 2.2 以降では、リアルタイムシグナルのう ち最初の 3つが使われる (signal(7) 参照)。 それ以前のカーネルでは SIGUSR1 と SIGUSR2 が 使われる。 アプリケーションは、スレッド実装で利用されているシグナルを どれも使わないよ うにしなければならない。 - スレッド間でプロセス ID を共有しない (実際には LinuxThreads のスレッドは通常よりは情報 を共有するプロセスとして 実装されているが、一つの共通のプロセス ID を共有してはいな い)。 (管理スレッドを含む) LinuxThreads スレッドは ps(1) を使うと別のプロセスのように見 える。 LinuxThreads の実装では POSIX.1 仕様から逸脱している点が いくつかある。以下に示すような点 がある: - getpid(2) を呼び出したときに、スレッド毎に異なる値が返される。 - メインスレッド以外のスレッドで getppid(2) を呼び出すと、管理スレッドのプロセス ID が返 される。 本当は、これらのスレッドで getppid(2) を呼んだ場合にはメインスレッドでの getppid(2) と同じ値が返るべきである。 - あるスレッドが fork(2) を使って新しい子プロセスを作成した場合、 どのスレッドでもこの子 プロセスを wait(2) できるべきである。しかしながら、この実装では子プロセスを作成した ス レッドだけがこの子プロセスを wait(2) できる。 - あるスレッドが execve(2) を呼び出した場合、他のスレッドは全て終了される (POSIX.1 の仕 様通り)。 しかしながら、新しいプロセスは execve(2) を呼んだスレッドと同じ PID を持 つ。正しくは メインスレッドと同じ PID を持つべきである。 - スレッド間でユーザー ID とグループ ID が共有されない このことは、set-user-ID プログラム で面倒な事態を招いたり、 アプリケーションが seteuid(2) などを使って信用情報 (credentials) を変更した場合に Pthreads 関数が失敗する原因となる。 - スレッド間で共通のセッション ID やプロセスグループ ID を共有しない。 - スレッド間で fcntl(2) を使って作成されるレコードロックを共有しない。 - times(2) と getrusage(2) が返す情報がプロセス全体の情報でなくスレッド単位の情報であ る。 - スレッド間でセマフォのアンドゥ値 (semop(2) 参照) を共有しない。 - スレッド間でインターバルタイマーを共有しない。 - スレッドは共通の nice 値を共有しない。 - POSXI.1 では、全体としてのプロセスに送られるシグナルと、 個別のスレッドに送られるシグナ ルを区別して考えている。 POSIX.1 によると、プロセスに送られたシグナル (例えば kill(2) を使って送る) は、そのプロセスに属すスレッドのうち 勝手に (arbitrarily) に選択された一 つのスレッドにより処理される ことになっている。LinuxThreads はプロセスに送られるシグナ ルの 概念に対応しておらず、シグナルは特定のスレッドにだけ送ることができる。 - スレッドはそれぞれの独自の代替シグナルスタックの設定を持つ。 しかし、新しいスレッドの代 替シグナルスタックの設定は そのスレッドを作成したスレッドからコピーされ、そのため ス レッドは最初は一つの代替シグナルスタックを共有する。 (仕様では、新しいスレッドは代替シ グナルスタックが定義されていない状態 で開始されるべきとされている。 2つのスレッドが共有 されている代替シグナルスタック上で同時に シグナルの処理を行った場合、予測不可能なプログ ラムのエラーが 起こり得る。) NPTL NPTL では、一つのプロセスの全てのスレッドは同じスレッドグループ に属する; スレッドグループ の全メンバーは同じ PID を共有する。 NPTL は管理スレッド (manager thread) を利用しない。 NPTL は内部でリアルタイムシグナルのうち最初の 2つの番号を使用しており (signal(7) 参 照)、これらのシグナルはアプリケーションでは使用できない。 NPTL にも POSIX.1 に準拠していない点が少なくとも一つある: - スレッドは共通の nice 値を共有しない。 NPTL の標準非準拠な点のうちいくつかは以前のカーネルでのみ発生する: - times(2) と getrusage(2) が返す情報がプロセス全体の情報でなくスレッド単位の情報である (カーネル 2.6.9 で修正された)。 - スレッド間でリソース制限を共有しない (カーネル 2.6.10 で修正された)。 - スレッド間でインターバルタイマーを共有しない (カーネル 2.6.12 で修正された)。 - メインスレッドだけが setsid(2) を使って新しいセッションを開始することができる (カーネ ル 2.6.16 で修正された)。 - メインスレッドだけが setpgid(2) を使ってそのプロセスをプロセスグループリーダーにするこ とができる (カーネル 2.6.16 で修正された)。 - スレッドはそれぞれの独自の代替シグナルスタックの設定を持つ。 しかし、新しいスレッドの代 替シグナルスタックの設定は そのスレッドを作成したスレッドからコピーされ、そのため ス レッドは最初は一つの代替シグナルスタックを共有する (カーネル 2.6.16 で修正された)。 NPTL の実装では以下の点についても注意すること: - スタックサイズのリソースのソフトリミット (setrlimit(2) の RLIMIT_STACK の説明を参照) が unlimited 以外の値に設定されている場合、ソフトリミットの値が 新しいスレッドのデフォ ルトのスタックサイズとなる。 設定を有効にするためには、プログラムを実行する前にリミット 値を 設定しておかなければならない。たいていは、シェルの組み込みコマンドの ulimit -s (C シェルでは limit stacksize) を使って設定する。 スレッド実装の判定 glibc 2.3.2 以降では、 getconf(1) コマンドを使って、 システムのスレッド実装を判定すること ができる。 以下に例を示す: bash$ getconf GNU_LIBPTHREAD_VERSION NPTL 2.3.4 ぞれ以前の glibc のバージョンでは、以下のようなコマンドで デフォルトのスレッド実装を判定す ることができる。 bash$ $( ldd /bin/ls | grep libc.so | awk '{print $3}' ) | \ egrep -i 'threads|ntpl' Native POSIX Threads Library by Ulrich Drepper et al スレッドの実装の選択: LD_ASSUME_KERNEL LinuxThreads と NPTL の両方をサポートしている glibc (glibc 2.3.x) があるシステムでは、 LD_ASSUME_KERNEL 環境変数を使うことで、動的リンカーがデフォルトで 選択するスレッド実装を上 書きすることができる。 この変数により、動的リンカーが特定のバージョンのカーネル上で 動作し ていると仮定するように指定する。 NPTL が必要とするサポート機能を提供していないカーネルバー ジョンを 指定することで、強制的に LinuxThreads を使うことができる (このようなことをする最 もありそうな場面は、 LinuxThreads の標準非準拠な振舞いに依存する (壊れた) アプリケーション を動作させる場合だろう)。 以下に例を示す: bash$ $( LD_ASSUME_KERNEL=2.2.5 ldd /bin/ls | grep libc.so | \ awk '{print $3}' ) | egrep -i 'threads|nptl' linuxthreads-0.10 by Xavier Leroy
関連項目
clone(2), futex(2), gettid(2), futex(7), sigevent(7), signal(7), pthreads の各種マニュアルページ、例えば: pthread_attr_init(3), pthread_atfork(3), pthread_cancel(3), pthread_cleanup_push(3), pthread_cond_signal(3), pthread_cond_wait(3), pthread_create(3), pthread_detach(3), pthread_equal(3), pthread_exit(3), pthread_key_create(3), pthread_kill(3), pthread_mutex_lock(3), pthread_mutex_unlock(3), pthread_once(3), pthread_setcancelstate(3), pthread_setcanceltype(3), pthread_setspecific(3), pthread_sigmask(3), pthread_sigqueue(3), and pthread_testcancel(3)
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。