Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么不像pthread\u mutex\u t&;互斥?_C++_Linux_Multithreading_C++11 - Fatal编程技术网

C++ 为什么不像pthread\u mutex\u t&;互斥?

C++ 为什么不像pthread\u mutex\u t&;互斥?,c++,linux,multithreading,c++11,C++,Linux,Multithreading,C++11,我在并发程序中使用了相当多的pthreads,主要使用了自旋锁、互斥锁和条件变量 我开始研究使用std::thread和std::mutex进行多线程处理,我注意到pthreads中似乎没有与spinlock等价的东西 有人知道这是为什么吗 pthreads中似乎没有与spinlock等价的东西 在用户空间中,自旋锁通常被认为是错误的工具,因为在持有自旋锁时无法禁用线程抢占(与内核中不同)。这样,一个线程可以获取一个自旋锁,然后被抢占,导致所有其他试图获取自旋锁的线程不必要地自旋(如果这些线程具

我在并发程序中使用了相当多的pthreads,主要使用了自旋锁、互斥锁和条件变量

我开始研究使用std::thread和std::mutex进行多线程处理,我注意到pthreads中似乎没有与spinlock等价的东西

有人知道这是为什么吗

pthreads中似乎没有与spinlock等价的东西

在用户空间中,自旋锁通常被认为是错误的工具,因为在持有自旋锁时无法禁用线程抢占(与内核中不同)。这样,一个线程可以获取一个自旋锁,然后被抢占,导致所有其他试图获取自旋锁的线程不必要地自旋(如果这些线程具有更高的优先级,则可能导致死锁(等待I/O的线程可能在唤醒时获得优先级提升))。这种推理也适用于所有无锁数据结构,除非数据结构是真实的(除了
boost::spsc_queue
之外,实际有用的数据结构并不多)

在内核中,锁定了自旋锁的线程在释放自旋锁之前不能被抢占或中断。这就是为什么自旋锁在那里是合适的(当不能使用时)

在Linux上,可以通过使用独立的CPU内核和固定在这些独立内核上的FIFO实时线程来防止抢占(不确定是否完全抢占,但最近内核发生了这样的变化)。但这需要一个经过深思熟虑的内核/机器配置和一个旨在利用该配置的应用程序。尽管如此,人们还是将这种设置与用户空间中的无锁(但不是无等待)数据结构一起用于业务关键型应用程序


在Linux上,有一个自适应互斥体
PTHREAD\u mutex\u adaptive\u NP
,它在内核中阻塞之前旋转(类似于)。但是,不能通过
std::mutex
接口使用该互斥体,因为在初始化
pthread\u mutextatr\u t
之前,没有选项自定义不可移植的
pthread\u mutex\u t

通过
std::mutex
接口既不能启用进程共享、机动性、错误检查,也不能防止优先级反转。实际上,人们编写自己的
pthread\u mutex\u t
包装器,允许设置所需的互斥属性;以及相应的条件变量包装器。可以重复使用标准锁,如
std::unique_lock
std::lock_guard

在我看来,可以在
std::
api中设置所需的互斥和条件变量属性,比如为派生类提供一个
受保护的
构造函数来初始化该
本机句柄
,但是没有。这看起来是一个做特定于平台的事情的好主意,但是,派生类必须有一个构造函数才能正确地初始化它。在互斥体或条件变量初始化之后,
native\u handle
几乎没有用处。除非这个想法只是能够将
本机\u句柄
传递给(C语言)API,这些API需要指向初始化的
pthread\u mutex\t
的指针或引用


Boost/C++标准的另一个例子是不接受信号量,因为信号量太难上吊,互斥(本质上是一个二进制信号量)和条件变量是更基本、更灵活的同步原语,其中一个是


<> P>从C++标准的观点来看,这些可能是正确的决定,因为教育用户正确地使用所有的细微差别都是使用自旋锁和信号量的一个困难的任务。而高级用户可以抛出一个。

你是对的,std名称空间中没有自旋锁实现。旋转锁是一个很好的概念,但在用户空间中通常很差。操作系统不知道你的进程想要旋转,通常你会得到比使用互斥锁更糟糕的结果。需要注意的是,在一些平台上实现了乐观旋转,因此互斥可以做得非常好。此外,在每次循环迭代之间调整“暂停”的时间不是一件琐碎的事情,需要进行微调。TL;DR不要在用户空间中使用旋转锁,除非您确实确定自己在做什么


请看一下
std::atomic_flag
的示例,它可能会回答您的问题。@idclev463035818该示例经常被批评为幼稚。两种常见的优化是:
pause
指令在重试CAS之前,重试之间和失败时的推测性加载。@idclev463035818用户空间代码中的自旋锁通常被认为是一个坏主意。@Shawn:标准库是否仅用于“用户空间代码”,或者我们是否可以在其上实现库?“操作系统不知道您的进程想要旋转”这不是一个bug;这是一个功能:防止操作系统窃取您的时间片。如果您需要毫秒精度,最大限度地减少时间片被盗非常重要。无锁编码要求具有“互斥锁”“这让操作系统肮脏的小手远离我的CPU。在不需要在很长一段时间内维护锁或不存在太多争用(任务队列等)的位置使用自旋锁。工具可能被误用并不是禁止工具本身的好理由。@Nicolas你读过Linus链接的帖子吗?他提出了日程安排的问题…@Nicolas:spinlock可能是必要的,但不足以完成这类工作。使用自旋锁不会阻止调度器终止时间片,它的脏手无论如何都会干预。您还必须确保旋转线程(以及当前持有锁的线程)都保持计划状态,这需要