-->

86等值LWARX和STWCX(x86 equivalent for LWARX and STWCX

2019-06-26 06:44发布

我在寻找LWARX和STWCX的等效(如在PowerPC处理器中)或者实现在x86平台上类似的功能的一种方式。 此外,会在哪里找到了这样的事情最好的地方(锁定/无等待编程即好文章/网站/论坛)。


编辑
我想我可能需要提供更多的细节被假定它是我只是寻找一个CAS(比较和交换)操作。 我想要做的就是实现与可以被多个线程访问和更改智能指针无锁引用计数系统。 基本上,我需要一个方式来实现在x86处理器以下功能。

int* IncrementAndRetrieve(int **ptr)
{
  int val;
  int *pval;
  do
  {
    // fetch the pointer to the value
    pval = *ptr;

    // if its NULL, then just return NULL, the smart pointer
    // will then become NULL as well
    if(pval == NULL)
      return NULL;

    // Grab the reference count
    val = lwarx(pval);

    // make sure the pointer we grabbed the value from
    // is still the same one referred to by  'ptr'
    if(pval != *ptr)
      continue;

    // Increment the reference count via 'stwcx' if any other threads
    // have done anything that could potentially break then it should
    // fail and try again
  } while(!stwcx(pval, val + 1));
  return pval;
}

我真正需要的东西,模仿LWARX和STWCX相当准确地拉这一关(我不能想出一个办法与CompareExchange,交换要做到这一点,或添加功能,我发现迄今为x86)。

谢谢

Answer 1:

正如迈克尔·中提到的,你可能寻找的是cmpxchg指令。

值得指出的是很重要的,虽然是完成这个被称为的PPC方法加载链接/条件存储 (LL / SC),而x86架构使用比较和交换 (CAS)。 LL / SC具有这样的任何变化,以在经调节的地址的值比CAS更强语义将导致存储失败,即使其它变化替换具有相同值的负荷条件上的值。 CAS,而另一方面,就在这种情况下取​​得成功。 这被称为ABA问题(见CAS链接了解更多信息)。

如果您需要在x86架构的强大的语义,您可以通过使用x86s双宽度比较并交换(DWCAS)指令来近似cmpxchg8b ,或cmpxchg16b下x86_64的。 这使您可以在原子一次交换,而不只是往常的两个连续的自然大小“字样。 其基本思想是两个单词中的一个包含感兴趣的值,另外一个包含总是递增“突变计数”。 尽管这在技术上不消除问题,突变柜台尝试之间缠绕的可能性是如此之低,这对于大多数目的的合理的替代品。



Answer 2:

86不直接支持“乐观并发”像PPC那样-相反,86对并发性的支持是基于“锁定前缀”,见这里 。 (一些所谓的“原子”的指令,例如通过XCHG本质断言LOCK前缀真正得到他们的原子性,汇编代码的程序员是否已经实际编码与否)。 这不正是“防弹”,把它外交上(事实上,这是相当容易发生意外,我会说;-)。



Answer 3:

你可能寻找的指令CMPXCHG家庭。

你需要有一个锁定指令先于这些得到等价的行为。

看看这里为的什么可用的快速概述。

你可能会使用类似于这样结束:

mov ecx,dword ptr [esp+4]
mov edx,dword ptr [esp+8]
mov eax,dword ptr [esp+12]
lock cmpxchg dword ptr [ecx],edx
ret 12

你应该阅读本文 ...

编辑

为响应更新的问题,你希望做类似的升压shared_ptr的 ? 如果是这样,看看这些代码,并在该目录中的文件 - 他们一定会得到你开始。



Answer 4:

如果您是在64位,限制自己说堆1TB,可以包柜台到24未使用的顶部位。 如果你有字对齐的三分球底部的5位也可提供。

int* IncrementAndRetrieve(int **ptr)
{
  int val;
  int *unpacked;
  do
  {   
    val = *ptr;
    unpacked = unpack(val);

    if(unpacked == NULL)
      return NULL;
    // pointer is on the bottom
  } while(!cas(unpacked, val, val + 1));
  return unpacked;
}


Answer 5:

不知道是不是LWARX和STWCX无效整个高速缓存行,CAS和DCAS做。 这意味着除非你愿意扔掉大量的内存(64个字节为每个独立的“上锁”指针)你不会看到太大的起色,如果你真的推你的软件进入压力。 我见过的最好的结果到目前为止是当人们自觉casrificed 64B,刨光围绕它自己的结构(包装的东西,不会受争议的),把一切神韵:64b上的边界,并用明确的数据读写障碍。 高速缓存行失效可以花费约20至100个周期,使其成为一个真正的大问题PERF然后就锁避免。

此外,你必须准备不同的内存分配策略来管理无论是受控的泄漏(如果你能隔断码成逻辑“请求处理” - 一个请求“泄漏”,然后释放所有它的内存散末)或datailed分配管理所以处于争用一个结构永远不会接收存储由相同的结构/集合的元素realesed(防止ABA)。 一些的,可以是非常反直觉的,但它要么或支付GC的价格。



Answer 6:

你所要做的就不会工作,你所期望的方式。 什么你在上面可以实现用InterlockedIncrement函数(;:XADD装配Win32函数)来完成。

你的代码没有做你认为他们做的原因是,另一个线程仍然可以改变* PTR和stwcx的第二读取之间的值,而不stwcx无效。



文章来源: x86 equivalent for LWARX and STWCX