我已经将 pthreads 用于并发程序,主要使用自旋锁、互斥锁和条件变量。
我开始研究使用 std::thread 和 std::mutex 的多线程,我注意到 pthread 中似乎没有与自旋锁等效的东西。
有谁知道这是为什么?
最佳答案
there doesn't seem to be an equivalent to spinlock in pthreads.
自旋锁在用户空间中通常被认为是错误的工具,因为在持有自旋锁时无法禁用线程抢占(与内核中不同)。这样一个线程可以获取自旋锁然后被抢占,导致所有其他尝试获取自旋锁的线程不必要地自旋(如果这些线程具有更高的优先级,可能会导致死锁(等待 I/O 的线程可能会获得优先级)唤醒时增强))。这个推理也适用于所有无锁数据结构,除非数据结构确实是 wait-free (除了
boost::spsc_queue
之外,没有多少实际有用的)。在内核中,锁定自旋锁的线程在释放自旋锁之前不能被抢占或中断。这就是为什么自旋锁在那里是合适的(当
RCU
不能使用时)。在 Linux 上,可以通过使用隔离的 CPU 内核和固定到这些隔离内核的 FIFO 实时线程来防止抢占(不确定是否完全,但最近内核已朝着这种理想的效果进行了更改)。但这需要经过深思熟虑的内核/机器配置以及旨在利用该配置的应用程序。尽管如此,人们确实将这样的设置用于关键业务应用程序以及用户空间中的无锁(但不是无等待)数据结构。
在 Linux 上,有自适应互斥锁
PTHREAD_MUTEX_ADAPTIVE_NP
, 旋转 for a limited number of iterations在内核阻塞之前(类似于 InitializeCriticalSectionAndSpinCount
)。但是,不能通过 std::mutex
使用该互斥锁。界面,因为没有自定义非可移植的选项pthread_mutexattr_t
初始化前 pthread_mutex_t
.一个人无法通过
std::mutex
启用进程共享、稳健性、错误检查或优先级反转预防。界面。在实践中,人们编写自己的 pthread_mutex_t
包装器。它允许设置理想的互斥属性;以及相应的条件变量包装器。标准锁,如 std::unique_lock
和 std::lock_guard
可以重复使用。IMO,可以在
std::
中设置所需的互斥锁和条件变量属性。 API,例如提供 protected
派生类的构造函数将初始化该 native_handle
,但没有。那个 native_handle
做平台特定的东西看起来是个好主意,但是,派生类必须有一个构造函数才能适本地初始化它。互斥或条件变量初始化后,native_handle
几乎没用。除非这个想法只能通过 native_handle
到(C 语言)API 需要一个指针或对初始化的引用 pthread_mutex_t
.还有一个 Boost/C++ 标准不接受信号量的例子,因为信号量太大了,不能自挂,互斥量(本质上是一个二进制信号量)和条件变量是更基本和更灵活的同步原语,out其中一个semaphore can be built .
从 C++ 标准的角度来看,这些可能是正确的决定,因为教育用户正确使用自旋锁和信号量是一项艰巨的任务。而高级用户可以抽出一个 wrapper for
pthread_spinlock_t
with little effort .
关于c++ - 为什么没有像 pthread_mutex_t & std::mutex 那样的 std::等价于 pthread_spinlock_t?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61526837/