【问题标题】:Indirect atomic swap for struct with pointer带指针的结构的间接原子交换
【发布时间】:2020-06-09 15:58:46
【问题描述】:

我想自动交换定义为结构VValue 的两个大内存位置。由于结构的大小比long 大,因此没有架构支持直接比较和交换两个结构。但是,一种方法是交换两个结构的指针并间接交换内存位置。

下面是我应该将oldValueb 交换的代码。 compare 和 swap 内置函数在 do-while 循环中使用,以确保在交换发生时 oldValue 的值不会被其他线程更改(此代码 sn-p 是更复杂的与其他条件交换。为简洁起见,条件被删除)。


  template<typename A, typename B, typename C, typename D>
  struct VStructType{
    A a;
    B b;
    C c;
    D d;

    VStructType () {
      ;

    }

    VStructType (A a, B b, C c, D d) {
      this->a = a;
      this->b = b;
      this->c = c;
      this->d = d;

    }

  };

  typedef VStructType<uint32_t,uint32_t,uint32_t,uint32_t> VValue;

  bool swap(VValue* oldValue, VValue b)
  {
    bool r = 0;
    VValue* c;
    VValue *w = new VValue();

    do{
      c = oldValue;
      w->a = b.a;
      w->b = b.b;
      w->c = b.c;
      w->d = b.d;
    } while (!(r = __sync_bool_compare_and_swap(&oldValue, c, w)));
    return r;
  }

  int main()
  {
    VValue oldValue = VValue(1,2,3,4);
    VValue b = VValue(10,12,2,8);
    swap(&oldValue, b);
  }

问题是在swap函数内部swap之后,oldValue的值变成了新的值,但是从swap函数返回后oldValue没有改变。似乎对oldValue 的引用是一个临时引用,当交换发生时,它只交换新引用而不是指向oldValue 的实际指针。将引用传递给__sync_bool_compare_and_swap 函数的原因是第一个参数是指向要与之比较值的变量的指针

我的问题:

1)有没有办法将oldValue的指针的指针直接传递给__sync_bool_compare_and_swap函数?

2) 当oldValue 是数组中的一个元素时,这种方法是否可行?

注意:使用g++ -latomic -std=gnu++11编译。

【问题讨论】:

  • 老实说,我什至不知道这段代码发生了什么。什么与什么交换?什么是新值,什么是旧值,为什么代码中突然出现“新”?为什么只交换指针就不行?
  • 我想将oldValueb 交换,两者都只是结构实例。由于我需要同步我的代码,我必须使用原子原语。
  • @Branky: 好的,没那么糟糕,但你收到了oldValue 作为调用者指针的副本(它引用相同的数据,但没有链接给调用者,因为它不是参考)。所以换出它的值对调用者来说并不重要,调用者的 pointer 不能改变,只能改变它指向的东西(并且只要函数的指针副本没有被重新分配指向别处)。如果要更改调用者的指针,则需要接收对指针或双指针的引用。
  • @Branky:Pointers are not references。如果您不了解它们之间的区别,那么现在考虑在 C++ 中实现复杂的无锁算法还为时过早。你需要先走路才能跑步。照原样,您的代码无论如何都无法工作;你想在调用者中交换一个指针,但是调用者没有一个指针,它给了你一个指向它的堆栈分配内存的指针。调用者中没有指向更改的指针。
  • 你有一个new,结果既不是由拥有类(如智能指针)管理,也不是与delete一起发布。您的函数中存在内存泄漏。

标签: c++ pass-by-reference compare-and-swap


【解决方案1】:

诀窍是将指向oldValue的指针的引用传递给交换函数,并按如下方式更改交换:

bool swap(VValue** oldValue, VValue b)
  {
    bool r = 0;
    VValue* c;
    VValue *w = new VValue();

    do{
      c = *oldValue;
      w->a = b.a;
      w->b = b.b;
      w->c = b.c;
      w->d = b.d;
    } while (!(r = __sync_bool_compare_and_swap(oldValue, c, w)));
    if(!r)
      delete w;
    return r;
  }

int main()
  {
    VValue* oldValue = new VValue(1,2,3,4);
    VValue b = VValue(10,12,2,8);
    swap(&oldValue, b);
  }

【讨论】:

  • 这不是书面的合法代码; swap 需要接受 VValue** 才能正常工作。此外,从语义上讲,您没有传递引用,而是传递了一个双指针。
  • b 保持不变。这是一个复杂的赋值操作,仅适用于原始拥有指针。
  • ''' b ''' 从来没有打算改变。这就是为什么它是按值传递的。此外,当性能至关重要时,我认为复杂的解决方案没有任何问题。
猜你喜欢
  • 2020-11-25
  • 1970-01-01
  • 1970-01-01
  • 2015-07-13
  • 2015-01-20
  • 2015-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多