基本的な非対称性は、ISO C ではワイド文字の幅が固定されていること (すべての文字で同じ) と、エンコーディングにシフト状態がないことが要求されていることです。対照的に、マルチバイト エンコーディングはロケールに依存し、文字幅やシフト状態が異なる場合があります。
4 つの関数はすべて、呼び出し間で保持される内部状態を持っています (mbstowcs
またwcstombs
、最初のシフト状態で終了する完全な文字列とは対照的に、指定されたバイト数のみを変換するため、保持する必要があります)。
文字列変換の場合、内部状態の構成要素に微妙な違いがあります。の場合mbstowcs
、ワイド文字の整数が 1 回の呼び出しで変換されます。これは、ワイド文字の幅が固定されていることn
と、呼び出しのパラメーターがバイト単位ではなく文字単位で指定されているためです。対照的にwcstombs
、n
パラメーターはマルチバイト文字ではなくバイト単位で指定されます。したがって、保持される状態にwcstombs
は、シフト状態だけでなく、部分的に出力されたマルチバイト文字の残りの部分も含める必要があります。このように状態は複数の部分に分かれているため、その状態に対する操作 (ロードとストア) は、追加のロックなしでは典型的なアーキテクチャではアトミックにはなりません。
この時点で、"スレッド セーフ" は POSIX ではかなり技術的な意味を持っていること、つまり、並列呼び出しは論理的にシリアル化可能であることを思い出すことが重要です。並列使用が必ずしも非常に役立つというわけではありません。4 つの関数はすべて内部状態を保持するため、(一度に) 1 つの線形文字列を左から右に処理し、呼び出しを複数のスレッドに分散する呼び出し元を想像するのは困難です。これは、ISO C 89/90 の Amendment 1のmbrtowc
、wcrtomb
、mbsrtowcs
およびの導入によって証明されており、フラグは特に「再入可能」を表しています。wcstombs
r
「原子的にアクセス可能な」内部状態を持つことで、それぞれの呼び出しをスレッドセーフな方法で実装しやすくする理由を正確に説明することはできません (1 回の呼び出し中に複数のアクセス、ロード、ストアが必要になる場合があるため)。しかし、おそらくそれは、追加のロック (およびリロード) の負担が、実際のシフト状態が発生しているほとんどアクセスされないコード ブランチにのみ課されるためです。
説明する別のキャッチもあります。並行スレッドは、ロケールsetlocale
の文字エンコーディング ( ) カテゴリの変更を呼び出すことができます。LC_CTYPE
ISO C 標準では、そのようなアクションによって現在の状態 (および、 を使用して適切にキャプチャされた状態でさえもwcrtomb
) が未定義になることが規定されています。これは、異なるロケールのシフト状態が、有用な方法または指定された方法で互いにマッピングされない可能性があるためです。これはスレッド化されたシナリオであり、"再入可能" ファミリの関数でさえ壊れる可能性がありますが、ロケール設定は呼び出しごとにキャッシュできるため、正式にスレッドセーフな実装に必ずしも障害をもたらすわけではありません。