yohhoyの日記

技術的メモをしていきたい日記

C11/C++11/POSIXスレッドAPI比較

C11標準ライブラリ、C++11標準ライブラリ、POSIXスレッドのスレッドライブラリ(Pthreads) API比較。

各スレッドライブラリAPIを、“スレッド”、“CallOnce”、“排他制御(mutex)”、“条件変数(condition variable)”、“TLS(Thread Local Storage)”、その他機能に分類して比較する。表記簡略化のためC++11標準ライブラリは名前空間stdを省略している。

概略

  • C11はISO/IEC JTC1/SC22/WG14 N1570、C++11はISO/IEC JTC1/SC22/WG21 N3337、POSIXIEEE Std 1003.1-2008に基づく。
  • C11標準ライブラリとPOSIXスレッドライブラリのAPI体系はほぼ同一。*1
  • C++11標準ライブラリはC11標準ライブラリ提供のスレッドサポート機能を包含し、C++言語機能テンプレートの利用によって利便性向上と型安全性を提供する。

ヘッダファイル

各スレッドライブラリにおいて機能別にincludeする必要のあるヘッダファイル。

C11 C++11 POSIX
スレッド threads.h thread pthreads.h
time.h
sched.h
CallOnce threads.h mutex pthreads.h
排他制御 threads.h mutex pthreads.h
条件変数 threads.h condition_variable pthreads.h
TLS 言語組込
threads.h
言語組込 pthreads.h
その他 - future -

C11におけるTLSは言語組み込み機能+標準ライブラリサポートで構成される。
C++11におけるTLSは言語組み込み機能のため、特定のヘッダincludeを必要としない。

スレッド

スレッドオブジェクトを表現する型と呼出可能な関数シグネチャ、スレッド作成/待機/比較といった操作を行う関数群。

C11 C++11 POSIX
thrd_t型 threadクラス pthread_t型
int (*)(void*) 任意の関数オブジェクト void* (*)(void*)
thrd_create threadコンストラク pthread_create
thrd_join thread::join pthread_join
thrd_detach thread::detach pthread_detach
thrd_exit 関数オブジェクトからのreturn pthread_exit
thrd_current this_thread::get_id pthread_self
thrd_equal thread::get_id と
thread::id::operator=
pthread_equal
thrd_sleep this_thread::sleep_for
this_thread::sleep_until
nanosleep[time.h]
thrd_yield this_thread::yield sched_yield[sched.h]

C11およびPOSIXではスレッド作成(create)関数に指定したユーザ定義関数の戻り値を、該当スレッドに対する待機(join)関数の戻り値として取得できる。
C++11では別スレッドにて実行された関数オブジェクトの戻り値は破棄される。スレッド間での値受け渡しを実装するには、別途future/promiseクラス[標準ヘッダfuture]を利用する必要がある。(→id:yohhoy:20120131)
スレッドキャンセル処理はPOSIXでのみ提供される。C11およびC++11において相当機能が必要な場合、条件変数等を用いて別途実装する必要がある。

CallOnce

CallOnce処理を実現するためのフラグ型と初期化定数、呼出可能な関数シグネチャとCallOnce関数。

C11 C++11 POSIX
once_flag型 once_flag型 pthread_once_t型
ONCE_FLAG_INITマクロ - PTHREAD_ONCE_INITマクロ
void (*)(void) 任意の関数オブジェクト void (*)(void)
call_once call_once pthread_once

C++11におけるフラグ型once_flagはconstexprなデフォルトコンストラクタを持つため、特に初期化定数を必要としない。

排他制御

ミューテックスオブジェクトを表現する型と、ミューテックスのロック獲得/開放といった操作を行う関数群。C++11列のMutexは具体的なクラス名ではなく、mutex, recursive_mutex, timed_mutex, recursive_timed_mutex のいずれかを表す*2

C11 C++11 POSIX
mtx_t型 Mutexクラス pthread_mutex_t型
mtx_init Mutexコンストラク pthread_mutex_init
mtx_destroy Mutexデストラク pthread_mutex_destroy
mtx_lock Mutex::lock pthread_mutex_lock
mtx_unlock Mutex::unlock pthread_mutex_unlock
mtx_trylock Mutex::try_lock pthread_mutex_trylock
mtx_timedlock Mutex::try_lock_for
Mutex::try_lock_until
pthread_mutex_timedlock

Reader-Writerロック(pthread_rwlock_*)やスピンロック(pthread_spin_*)はPOSIXでのみ提供される。C11およびC++11において相当機能が必要な場合、条件変数やatomic変数等を用いて別途実装する必要がある。

ミューテックスの属性

ミューテックスオブジェクトの能力/属性; 再帰, タイムアウト付き待機 の表現方法。

  • C11:初期化関数mtx_initの引数にて列挙型値mtx_plain, mtx_timed, mtx_recursiveまたはそのビット和を指定する*3
  • C++11:クラス型によって表現する。mutex, recursive_mutex, timed_mutex, recursive_timed_mutexクラスが提供される。
  • POSIX:初期化関数thread_mutex_initの引数にてpthread_mutexattr_tオブジェクトを指定する。再帰ミューテックスの場合、同pthread_mutexattr_tオブジェクトへpthread_mutexattr_settype関数にてPTHREAD_MUTEX_RECURSIVE定数を指定する。

条件変数

条件変数オブジェクトを表現する型と、条件変数への通知/待機といった操作を行う関数群。

C11 C++11 POSIX
cnd_t型 condition_variableクラス pthread_cond_t型
cnd_init condition_variableコンストラク pthread_cond_init
cnd_destroy condition_variableデストラク pthread_cond_destroy
cnd_signal condition_variable::notify_one pthread_cond_signal
cnd_broadcast condition_variable::notify_all pthread_cond_broadcast
cnd_wait condition_variable::wait pthread_cond_wait
cnd_timedwait condition_variable::wait_until
condition_variable::wait_for
pthread_cond_timedwait

C++11における条件変数オブジェクトにはcondition_variable_anyも存在する(表中では省略)。
バリア同期(pthread_barrier_*)はPOSIXでのみ提供される。C11およびC++11において相当機能が必要な場合、条件変数等を用いて別途実装する必要がある。*4

TLS

TLS値を表現するキー型と、TLS値の設定/取得といった操作を行う関数群。

C11 C++11 POSIX
_Thread_local記憶域指定子
tss_t型
thread_local記憶域指定子 pthread_key_t型
任意の型
void *
任意の型 void *
(言語組込)
tss_create
(言語組込) pthread_key_create
(言語組込)
tss_delete
(言語組込) pthread_key_delete
(変数write)
tss_set
(変数write) pthread_setspecific
(変数read)
tss_get
(変数read) pthread_getspecific

POSIXにおけるTLS(TSS; Thread Specific Storage)は、キーと値(void*型)を紐付ける方式で実現される。
C++11におけるTLSは言語組み込み機能のため、変数に対してthread_local指定を行うことで任意の型を利用できる。またcreate/delete相当は処理系により行われ、get/setは通常変数と同様に単に変数アクセスでよい。
C11におけるTLS/TSSは、_Thread_local指定による言語組み込みのスカラ型サポートと、標準ライブラリ関数によるデストラクト処理を伴うvoid*型のサポートで実現される。また標準ヘッダthreads.hでは、下記のthread_localマクロを定義する。

#define thread_local  _Thread_local

その他

タイムアウト付き待機関数で利用する時刻/時間表現型と現在時刻取得関数。

C11 C++11 POSIX
struct timespec型 chrono::time_point<Clock, Duration>クラス
chrono::duration<Rep, Period>クラス
struct timespec型
timespec_get[time.h] chrono::system_clock::now[chrono]
chrono::seconds型 など[chrono]
clock_gettime[time.h]

C11の標準ヘッダthreads.hではtime.hをincludeすることが標準で要求される。


関連URL

*1:余談:C標準ライブラリでの偏執的な関数名の短さはどこから来るの…

*2:try_lock_for, try_lock_untilメンバ関数はtimed_mutexとrecursive_timed_mutexクラスにのみ存在。

*3:C11標準規格が許容するのは次の4種類:mtx_plain, mtx_timed, mtx_plain|mtx_recursive, mtx_timed|mtx_recursive

*4:参考実装:http://www.boost.org/boost/thread/barrier.hpp