yohhoyの日記

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

Cストリーム入出力関数とスレッド安全性

C標準ライブラリの stdio.h ヘッダで提供されるストリーム入出力関数において、複数スレッドから同時に対象ストリーム入出力操作を行ったときの振る舞い(スレッド安全性)に関するメモ。

まとめ:

  • C99以前:POSIX準拠システムならばスレッド安全である。(それ以外は処理系の仕様を参照)
  • C11以降:C言語仕様によりスレッド安全性が保証される。この振る舞いに関してはPOSIX相当。

POSIX

POSIXシステムが定める全関数は基本的にスレッド安全(Thread-Safe)であると定義され、C標準ライブラリの関数fgetc()やprintf()などを用いて、異なるスレッドから同時にストリーム入出力操作を行ってもよい。*1

POSIX規格(IEEE Std 1003.1-2008)より"Thread-Safe"の定義、およびflockfile/funlockfile関数仕様から一部引用(下線部は強調)。

3.399 Thread-Safe
A function that may be safely invoked concurrently by multiple threads. Each function defined in the System Interfaces volume of POSIX.1-2008 is thread-safe unless explicitly stated otherwise. Examples are any "pure" function, a function which holds a mutex locked while it is accessing static storage, or objects shared among threads.

http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_399

SYNOPSIS

#include <stdio.h>
void flockfile(FILE *file);
int ftrylockfile(FILE *file);
void funlockfile(FILE *file);

DESCRIPTION
These functions shall provide for explicit application-level locking of stdio (FILE *) objects. These functions can be used by a thread to delineate a sequence of I/O statements that are executed as a unit.
(snip)
All functions that reference (FILE *) objects shall behave as if they use flockfile() and funlockfile() internally to obtain ownership of these (FILE *) objects.

http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html

C11

C11標準ライブラリにおけるストリーム入出力操作のスレッド安全性に関しては、POSIXシステムと同様の定義がなされている。ただしPOSIXとは異なり、アプリケーションコードから明示的にストリーム関連ロックを操作する関数は提供されない。

N1570 7.21.2/p7-8より引用。

7 Each stream has an associated lock that is used to prevent data races when multiple threads of execution access a stream, and to restrict the interleaving of stream operations performed by multiple threads. Only one thread may hold this lock at a time. The lock is reentrant: a single thread may hold the lock multiple times at a given time.
8 All functions that read, write, position, or query the position of a stream lock the stream before accessing it. They release the lock associated with the stream when the access is complete.

関連URL

*1:関数名に"_unlocked"接尾辞がついた関数は、性能向上を目的として意図的に「スレッド安全でない」仕様となっている。POSIX規格が定めるのはgetc_unlocked(), getchar_unlocked(), putc_unlocked(), putchar_unlocked()の4つ。