4.57 スレッドセーフな C ライブラリ関数

以下の表は、スレッドセーフな C ライブラリ関数の一覧です。

表 4-1 スレッドセーフな関数

関数 説明
calloc()、free()、malloc()、realloc()
_mutex_* 関数が実装されている場合、ヒープ関数はスレッドセーフです。
すべてのスレッドが 1 つのヒープを共有し、ミューテックスを使用して同時アクセス時にデータの破損を避けます。ヒープに関するロック処理は、個々のヒープ実装自体によって固有の方法で行われます。ユーザが独自にアロケータを指定する場合は、そのアロケータでも独自のロック処理を行う必要があります。これにより、単一のミューテックスを使用してヒープ全体を保護する(粗粒ロック)のではなく、必要に応じて細粒ロックを行うことができます。
alloca()
alloca() は、スタック上のメモリを割り当てるのでスレッドセーフです。
abort()、raise()、signal()、fenv.h
ARM® 信号処理関数と浮動小数点の例外のトラップはスレッドセーフです。
シグナルハンドラおよび浮動小数点トラップの設定はプロセス全体を通じてグローバルです。また、これらの設定は、ロックによって保護されています。複数のスレッドによって signal() 関数または fenv.h 関数が同時に呼び出されても、データは破損しません。ただし、関数呼び出しの影響は、呼び出し側スレッドだけではなく、すべてのスレッドに及ぶので注意して下さい。
clearerr()、fclose()、feof()、ferror()、fflush()、fgetc()、fgetpos()、fgets()、fopen()、fputc()、fputs()、fread()、freopen()、fseek()、fsetpos()、ftell()、fwrite()、getc()、getchar()、gets()、perror()、putc()、putchar()、puts()、rewind()、setbuf()、setvbuf()、tmpfile()、tmpnam()、ungetc()
_mutex_* 関数が実装されている場合、stdio ライブラリはスレッドセーフです。
個々のストリームはロックにより保護されているので、2 つのスレッドは互いに割り込むことなく、それぞれが stdio ストリームを開いて利用できます。
2 つのスレッドによって同じストリームの読み出しまたは書き込みが実行される場合は、fgetc() および fputc() レベルでロックすることによりデータ破損を回避できます。ただし、各スレッドによって出力される文字がインターリーブされ、混乱する可能性があります。

tmpnam() には、スタティックバッファも格納されますが、使用されるのは引数が NULL の場合だけです。使用する tmpnam() を確実にスレッドセーフにするには、独自のバッファ領域を指定します。
fprintf()、printf()、vfprintf()、vprintf()、fscanf()、scanf()
これらの関数を使用する場合、以下のようになります。
  • 標準 C の printf() および scanf() 関数は stdio を使用するため、スレッドセーフです。
  • 標準 C の printf() 関数は、マルチスレッドプログラムで呼び出された場合、ロケール設定の変更の影響を受けます。
clock() clock() には、プログラム起動時に一度書き込まれると、その後は読み出し専用となるスタティックデータが格納されます。したがって、ライブラリ初期化時にまだ別の他のスレッドが実行されていなければ、clock() はスレッドセーフです。
errno
errno はスレッドセーフです。
各スレッドでは、__user_perthread_libspace ブロックに独自の errno が格納されます。そのため、各スレッドは、errno 設定関数を個別に呼び出してから、他のスレッドからの割り込みを受けることなく errno をチェックできます。
atexit()
atexit() に保持されている終了関数のリストは、プロセス内でグローバルです。また、ロックによって保護されています。
最悪の場合、複数のスレッドが atexit() を呼び出すと、呼び出される終了関数の順序は保証されません。
abs()、acos()、asin()、atan()、atan2()、atof()、atol()、atoi()、bsearch()、ceil()、cos()、cosh()、difftime()、div()、exp()、fabs()、floor()、fmod()、frexp()、labs()、ldexp()、ldiv()、log()、log10()、memchr()、memcmp()、memcpy()、memmove()、memset()、mktime()、modf()、pow()、qsort()、sin()、sinh()、sqrt()、strcat()、strchr()、strcmp()、strcpy()、strcspn()、strlcat()、strlcpy()、strlen()、strncat()、strncmp()、strncpy()、strpbrk()、strrchr()、strspn()、strstr()、strxfrm()、tan()、tanh()
これらの関数は本質的にスレッドセーフです。
longjmp()、setjmp()
setjmp() および longjmp() ではデータが __user_libspace に格納されますが、スレッドセーフな __alloca_* 関数が呼び出されます。
remove()、rename()、time()
これらの関数は、 ARM デバッグ環境と通信する割り込みを使用します。通常、実際のアプリケーションではこれらの関数を再実装する必要があります。
snprintf()、sprintf()、vsnprintf()、vsprintf()、sscanf()、isalnum()、isalpha()、iscntrl()、isdigit()、isgraph()、islower()、isprint()、ispunct()、isspace()、isupper()、isxdigit()、tolower()、toupper()、strcoll()、strtod()、strtol()、strtoul()、strftime()
これらの関数を使用した場合、文字列ベース関数はロケール設定を読み出します。通常、これらの関数はスレッドセーフです。ただし、セッションの途中でロケールを変更する場合は、これらの関数に影響が及ばないようにする必要があります。
sprintf()sscanf() などの文字列ベース関数は、stdio ライブラリを使用しません。
stdin、stdout、stderr これらの関数は、スレッドセーフです。
関連する概念
1.5.11 ARM C ライブラリでのスレッドセーフティ
関連する参考文書
4.2 alloca()
非機密扱いPDF file icon PDF 版ARM DUI0808CJ
Copyright © 2014, 2015 ARM.All rights reserved.