6

Posix の堅牢なミューテックスを使用して、異なるプロセス間で共有リソースを保護することを考えています (Linux 上)。ただし、さまざまなシナリオでの安全性については疑問があります。次の質問があります。

  1. 堅牢なミューテックスはカーネルまたはユーザー コードに実装されていますか?

  2. 後者の場合、pthread_mutex_lock または pthread_mutex_unlock の呼び出し中、および共有 pthread_mutex データ構造の更新中にプロセスがクラッシュした場合はどうなりますか?

    プロセスがミューテックスをロックして停止した場合、別のプロセスのスレッドが起動され、EOWNERDEAD が返されることを理解しています。しかし、(共有メモリ内の) pthread_mutex データ構造が更新されているまさにそのときにプロセスが停止した場合 (まれなケース) はどうなるでしょうか? その場合、ミューテックスは壊れますか? pthread_mutex 関数を呼び出した場合、同じ共有メモリにマップされている別のプロセスはどうなりますか? この場合、ミューテックスは回復できますか?

  3. この質問は、PTHREAD_PROCESS_SHARED 属性を持つすべての pthread オブジェクトに適用されます。pthread_mutex_lock、pthread_mutex_unlock、pthread_cond_signal などの関数を、異なるプロセスから同じオブジェクトに対して同時に呼び出すことは安全ですか? それらは異なるプロセス間でスレッドセーフですか?

4

2 に答える 2

11

pthreads のマンページから:

 Over time, two threading implementations have been provided by the
   GNU C library on Linux:

   LinuxThreads
          This is the original Pthreads implementation.  Since glibc
          2.4, this implementation is no longer supported.

   NPTL (Native POSIX Threads Library)
          This is the modern Pthreads implementation.  By comparison
          with LinuxThreads, NPTL provides closer conformance to the
          requirements of the POSIX.1 specification and better
          performance when creating large numbers of threads.  NPTL is
          available since glibc 2.3.2, and requires features that are
          present in the Linux 2.6 kernel.

   Both of these are so-called 1:1 implementations, meaning that each
   thread maps to a kernel scheduling entity.  Both threading
   implementations employ the Linux clone(2) system call.  In NPTL,
   thread synchronization primitives (mutexes, thread joining, and so
   on) are implemented using the Linux futex(2) system call.

そして man futex(7) から:

   In its bare form, a futex is an aligned integer which is touched only
   by atomic assembler instructions.  Processes can share this integer
   using mmap(2), via shared memory segments or because they share
   memory space, in which case the application is commonly called
   multithreaded.

ここにある追加の発言:

(共有メモリでどのように機能するのか疑問に思っている場合: Futex は物理アドレスをキーとしています)

futex要約すると、Linux は、実際にユーザー プロセスのアドレス空間に存在する「ネイティブ」プリミティブの上に pthread を実装することを決定しました。共有同期プリミティブの場合、これは共有メモリとなり、1 つのプロセスが終了した後も、他の​​プロセスはそれを見ることができます。

プロセスが終了した場合はどうなりますか? Ingo Molnar は、まさにそれについてRobust Futexesという記事を書きました。関連する引用:

堅牢な Futex

リストへの追加とリストからの削除は glibc によって futex が取得された後に行われるため、スレッド (またはプロセス) がそこで停止し、futex がハングしたままになるためのいくつかの命令ウィンドウがあります。この可能性から保護するために、ユーザー空間 (glibc) はスレッドごとの単純な 'list_op_pending' フィールドも維持し、スレッドがロックを取得した後で終了した場合にカーネルがクリーンアップできるようにしますが、それ自体がリストに追加される直前です。glibc は、futex を取得しようとする前にこの list_op_pending フィールドを設定し、list-add (または list-remove) が終了した後にクリアします。


概要

これにより、他のプラットフォームに移行する場所は無限にあります。Linux の実装は、少なくとも、堅牢性に対する私たちの常識的な期待に応えるために細心の注意を払っていると言えば十分です。

他のオペレーティング システムは通常、そもそもカーネル ベースの同期プリミティブに依存していることを考えると、それらの実装がより自然に堅牢になると考えるのは理にかなっています。

于 2013-10-16T08:20:03.457 に答える