【问题标题】:Assigning return value of an atomic function分配原子函数的返回值
【发布时间】:2014-02-05 19:01:20
【问题描述】:

我正在尝试实现一个屏障函数,这样当一个线程调用waitBarrier() 时,它会等到所有其他n 线程都调用了该函数,之后一切都会继续,即一种同步构造。

我有以下代码:

int i = 0; // Shared variable. Initialized as 0 at the beginning.

waitBarrier() {

  // CAS = Compare-and-swap, the first argument holds "old_val" the second the new
  i = CAS(i, i+1);

  // Spin until all n threads (number of all threads known prior) have been "here"
  while (i != n) {}

}

如果被n 线程访问,这个函数会起作用吗?原子函数返回值的赋值是原子的吗?还是会出现竞争条件?

【问题讨论】:

  • 如果它工作,它会工作很糟糕,(自旋锁)。
  • 好吧,假设所有线程都等待很短的时间,它应该是相当有效的。
  • 等待的线程越多,留给其他线程的 CPU 和内存带宽就越少。

标签: multithreading locking race-condition spinlock compare-and-swap


【解决方案1】:

首先你必须指定一个寄存器的地址,这是你要比较和交换的值。这可以通过以下任一方式完成:

CAS(int* reg, int oldValue, int newValue)

reg.CAS(int oldValue, int newValue)

假设您现在的线路是:

i = i.CAS(i, i+1)

想象两个线程同时调用waitBarrier()。 假设原子函数的参数被非原子地评估,即两个线程实际上都会调用i.CAS(0,1)

无论谁先执行原子调用,都会成功地将共享变量 i 设置为 1。 由于 CAS 总是返回旧值,因此通过赋值 i = OLD_VALUE_OF_i 您实际上将共享变量重置为 0。 不仅如此,想象一下你会完全忽略这个赋值,只是进行了 CAS 调用,无论谁执行 CAS 第二个线程,都会将共享值的值(现在为 1)与 i 的初始值(在评估时参数为 0) 将失败,因此共享变量只会增加一次!

考虑到这两个方面,您的代码必须如下所示:

int i = 0;

waitBarrier() {
  // Atomically increment the shared value i by 1
  do {
    int value = i;
  } while (CAS(i, value, value + 1));

  // Wait until all threads have passed the barrier
  while (i != n) {}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-07
    • 2012-09-26
    相关资源
    最近更新 更多