performance - 原子 memcpy 建议

标签 performance scalability atomic memcpy


在测试程序的可扩展性时,我遇到了必须将 memcpy 操作设置为原子操作的情况。我必须将 64 字节的数据从一个位置复制到另一个位置。
我遇到了一种解决方案,即使用旋转变量:

struct record{
    volatile int startFlag;
    char data[64];
    volatile int doneFlag;
};

伪代码如下

struct record *node;
if ( node->startFlag ==0 ) {  // testing the flag 
    if( CompareAndSwap(node->startFlag , 0 ,1 ) ) {  // all thread tries to set, only one will get success and perform memcpy operation 
        memcpy(destination,source,NoOfBytes);
        node->doneFlag = 1; // spinning variable for other thread, those failed in CompAndSwap 
    }
    else {
         while ( node->doneFlag==0 ) { // other thread spinning 
          ; // spin around and/or use back-off policy  
         }
   }}

这可以作为原子 memcpy 执行吗?尽管如果执行 memcpy 的线程被抢占(在 memcpy 之前或之后但在设置 didFlag 之前),则其他线程将继续旋转。或者可以做什么来使这个原子化。
情况就像其他线程必须等待,除非数据被复制,因为它们必须与插入的数据和自己的数据进行比较。
我在 startFlag 的情况下使用测试和测试和设置方法来减少一些昂贵的原子操作。 自旋锁也是可扩展的,但我已经测量到原子调用比自旋锁具有更好的性能,而且我正在寻找此代码片段中可能出现的问题。 由于我使用自己的内存管理器,因此内存分配和免费调用对我来说成本高昂,因此使用另一个缓冲区并复制其中的内容,然后设置指针(因为指针大小处于原子操作下)成本高昂,因为它会需要许多 mem-alloc 和 mem-free 调用。

编辑我没有使用互斥锁,因为它们似乎不可可扩展而且这只是程序的一部分,所以关键部分不是这么小(我知道对于较大的关键部分很难使用原子操作)。

最佳答案

您的代码片段肯定已损坏。 node->startFlag 上有一场竞赛

不幸的是,没有原子方法来复制 64 字节。我认为您在这里有很多选择。

  1. 以原子方式访问node->startFlag。我已经就这个主题写了几篇文章:herehere .
  2. 使用用户模式自旋锁保护整个事物。 Here's a post on the subject
  3. 使用类似 RCU 的方法。您可以阅读有关 RCU here 的信息。简而言之,这个想法是使用指针引用要复制的缓冲区。然后你就可以:
    1. 分配新缓冲区。
    2. 创建其内容(从您的源中进行 memcpy)。
    3. 自动用新缓冲区替换缓冲区。
    4. 等待所有访问旧缓冲区的线程到期并释放它。

希望有帮助。 亚历克斯。

关于performance - 原子 memcpy 建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6704252/

相关文章:

windows - 为什么我的代码执行得更慢?

c# - 是否可以在 Azure Cosmos DB 中对可扩展的关注者/关注关系进行建模?

sql - 在 GROUP BY 后连接一个字段

SharePoint 列表可扩展性

multithreading - CompareExchange可以用CompareAndSwap来实现吗?

C++11,std::atomic 在 clang 3.2 和 libc++ 中损坏了吗?

c++ - 为什么互斥锁与原子操作的不同之处在于前者是操作系统级别,后者是处理器级别?

performance - 使用 match_all VS 查询进行过滤

c# - 测试/提高多线程程序的性能

C++ hash_map find() 与 contains() 性能对比