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 被锁定在它们的物理地址上

总而言之,Linux 决定在其“本机”原语之上实现 pthread futex,该原语确实存在于用户进程地址空间中。对于共享同步原语,这将是共享内存,并且在一个进程死亡后,其他进程仍然可以看到它。

如果进程终止会发生什么?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 回答
0

按照此处的文档:http: //pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_getrobust.html,它确实读到在完全符合 POSIX 的操作系统中,具有健壮标志的共享互斥锁将以您的方式运行d 期望。

问题显然是并非所有操作系统都完全符合 POSIX。甚至那些自称的人也不行。进程共享互斥锁,特别是健壮的互斥锁,是那些通常不属于操作系统的 POSIX 实现的部分。

于 2018-08-03T09:33:36.097 回答