C++ 如何修复macOS pthread互斥锁的缓慢性能?

C++ 如何修复macOS pthread互斥锁的缓慢性能?,c++,multithreading,macos,pthreads,locking,C++,Multithreading,Macos,Pthreads,Locking,我有一个修改多线程程序中共享资源的函数。这个函数是线程接触共享资源的唯一地方,并且它只用于每个线程整体工作的一小部分 static int64_t AddToSharedResource(volatile int64_t* value, int64_t to_add) { int64_t result = *value; *value += to_add; return result; } 我想让我的应用程序线程安全,所以我在指令之间添加了一个简单的互斥锁 static

我有一个修改多线程程序中共享资源的函数。这个函数是线程接触共享资源的唯一地方,并且它只用于每个线程整体工作的一小部分

static int64_t
AddToSharedResource(volatile int64_t* value, int64_t to_add)
{
    int64_t result = *value;
    *value += to_add;
    return result;
}
我想让我的应用程序线程安全,所以我在指令之间添加了一个简单的互斥锁

static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

static int64_t
AddToSharedResource(volatile int64_t* value, int64_t to_add)
{
    pthread_mutex_lock(&lock);
    int64_t result = *value;
    *value += to_add;
    pthread_mutex_unlock(&lock);
    return result;
}
这样做会使我的程序速度慢10倍以上,甚至比单线程版本还要慢

在阅读更多内容后,这似乎是因为macOS实现,它使用而不是使用,并且在实现之间存在一定的权衡,但这种情况是性能较差的情况之一。然而,我之所以这样编写代码,是因为我已经在Win32中编写了程序(在Win32中,锁几乎不会造成任何性能损失),并且我还计划将该函数移植到Linux


有没有一种方法可以在不造成巨大瓶颈的情况下使此功能在macOS中线程安全,或者我需要重新设计平台层?

您的示例与之完全匹配。
原子操作应该比执行锁-修改-解锁舞蹈便宜得多,并具有允许指定精确的额外好处。

它看起来像是
std::Atomic::fetch\u add
(正如@Botje建议的那样)在我的体系结构上使用
lock
指令编译,而在互斥锁/解锁中围绕关键部分需要对内核进行两次实际调用(这似乎可以解释性能上的差异)

我对如何使用MacOS的API而不是C++的标准库生成相同的指令感兴趣(只是为了好玩)。在浏览了他们的文档之后,我看到了定义原子操作函数的标题

#include <libkern/OSAtomic.h>

static int64_t
AddToSharedResource(volatile int64_t* value, int64_t to_add)
{
    int64_t result = OSAtomicAdd64(to_add, value);
    return result - to_add;  // As we want the previous value.
}
#包括
静态int64\t
AddToSharedResource(volatile int64\u t*值,int64\u t to\u add)
{
int64_t result=OSAtomicAdd64(要添加,值);
返回result-to_add;//因为我们需要上一个值。
}
但是,这会产生一个弃用警告,建议改用C++的标准库

'OSAtomicAdd64' is deprecated: deprecated in macOS 10.12 - Use 
    std::atomic_fetch_add_explicit(std::memory_order_relaxed) 
    from <atomic> instead.
“OSAtomicAdd64”已弃用:在macOS 10.12中弃用-使用
std::原子\u获取\u添加\u显式(std::内存\u顺序\u松弛)

从。

如何将资源放置在内存中非常重要。我设法通过避免而不做任何其他更改来加速线程程序x10
alignas
在这种情况下是您的朋友。
AddToSharedResource(volatile int64_t*值,int64_t to_add)
-为什么指针
是volatile
?请注意,
volatile
并不意味着线程安全。不,如果您正确同步对资源的访问,您永远不需要
volatile
。Volatile用于编译器无法控制的变化,比如直接映射到某个硬件信号的内存地址。这不是Volatile的用途。它主要用于读取硬件寄存器等。这里的主要作用是防止编译器优化对指针的访问。你只是让你的代码运行得更慢了。@TEDLYNAH,我明白了!也许可以试一试!有趣的是,看看编译器能想出什么:谢谢你的建议!不过我得先仔细看看。您知道macOS的基本说明吗?我不太熟悉C++线程库;我通常直接调用系统调用。我看到叮当声有。。。也许可以用它来实现吗?:-)我想那是针对我的
pthreads
的基础。在Mac和Linux上,它几乎是一个很薄的包装器,但是有了适当的资源管理。blocks看起来更像std::async,并且两者都比std::atomic@TedLyngmo我真的很想知道std::atomic::fetch\u add
!由于MACOS使用<代码> pStult<代码>,所以可以使用系统调用来进行此操作,而不是使用C++ <代码>线程< /COD> >代码>原子< /COD>库。我只是好奇macOS上的底层调用是什么。原子操作精确地映射到您架构的原子CPU指令。