ここで、前のコメントについて詳しく説明する必要があります。@paercebalの答えは正しくありません。サンプルコードでは、パラメータであるはずのミューテックスが実際に渡されていないことに誰も気づいていませんでしたか?
私は結論に異議を唱えます、私は主張します:並行性の存在下で関数が安全であるためには、それは再入可能でなければなりません。したがって、並行セーフ(通常はスレッドセーフと記述されている)は、再入可能を意味します。
スレッドセーフでもリエントラントでも、引数については何も言えません。関数の同時実行について話しているのですが、不適切なパラメーターが使用されていると、それでも安全ではない可能性があります。
たとえば、memcpy()はスレッドセーフであり、(通常は)再入可能です。明らかに、2つの異なるスレッドから同じターゲットへのポインターを使用して呼び出された場合、期待どおりに機能しません。これがSGI定義のポイントであり、同じデータ構造へのアクセスがクライアントによって同期されるようにクライアントに責任を負わせます。
一般に、スレッドセーフな操作にパラメータを含めることは意味がないことを理解することが重要です。データベースプログラミングを行ったことがある場合は、理解できます。「アトミック」であり、ミューテックスまたはその他の手法によって保護される可能性のある概念は、必然的にユーザーの概念です。データベースでトランザクションを処理するには、中断のない複数の変更が必要になる場合があります。同期を保つ必要があるのはクライアントプログラマーだけですが、誰が言うことができますか?
重要なのは、「破損」がシリアル化されていない書き込みでコンピュータのメモリを台無しにする必要がないということです。個々の操作がすべてシリアル化されている場合でも、破損が発生する可能性があります。したがって、関数がスレッドセーフであるか、再入可能であるかを尋ねる場合、質問はすべての適切に分離された引数を意味します。結合された引数を使用することは反例を構成しません。
そこには多くのプログラミングシステムがあります。Ocamlはその1つであり、Pythonも同様に、再入可能でないコードがたくさん含まれていますが、グローバルロックを使用してスレッドアクセスをインターリーブしていると思います。これらのシステムは再入可能ではなく、スレッドセーフでも並行セーフでもありません。グローバルな同時実行を防ぐという理由だけで安全に動作します。
良い例はmallocです。再入可能ではなく、スレッドセーフでもありません。これは、グローバルリソース(ヒープ)にアクセスする必要があるためです。ロックを使用しても安全にはなりません。再入可能ではありません。mallocへのインターフェースが適切に設計されていれば、再入可能でスレッドセーフにすることが可能です。
malloc(heap*, size_t);
これで、単一ヒープへの共有アクセスをシリアル化する責任がクライアントに移るので、安全になります。特に、個別のヒープオブジェクトがある場合は、作業は必要ありません。共通ヒープが使用されている場合、クライアントはアクセスをシリアル化する必要があります。関数内でロックを使用するだけでは不十分です。mallocがヒープをロックしていると考えてください*。その後、シグナルが届き、同じポインターでmallocを呼び出します。デッドロック:シグナルは続行できず、クライアントも続行できません。中断されます。
一般的に言って、ロックはスレッドセーフにはなりません..クライアントが所有するリソースを不適切に管理しようとすることで、実際には安全性を破壊します。ロックはオブジェクトの製造元が行う必要があります。これは、作成されるオブジェクトの数とその使用方法を知っている唯一のコードです。