我正在用C编写一个程序。为了简单起见,我们可以说:有几个变量,许多线程都可以读写。每次写入其中一个时,它都是通过原子交换(GCC原子操作、同步和交换)写入的。我是否需要在每次读取其中一个变量时使用原子负载,或者原子写入是否足以避免在写入过程中读取数据?
注意,需要使用其中一个变量的数据的任何位置都会首先复制值:
int success = 0;
while ( !success ) {
int x = shared_x;
... work with x, result in y ...
success = cmp_swap( &shared_x, x, y );
}
我的问题不是关于数据竞赛,也就是说我不担心我会丢失数据。我担心的是,在我阅读它的过程中,共享_x的价值可能会发生变化。假设它是一个8字节的整数,这是否是一个潜在的问题:假设shared_x是一个64位整数,8字节。我的x=shared_x是否可能复制前4个字节,然后某个东西自动写入shared_x,然后此语句完成读取第二个4个字节。这将导致x包含旧值shared_x的前4个字节,以及新shared_x的最后4个字节。我怀疑原子交换中存在内存障碍(http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html-使用_sync_bool_compare_和_swap)足以防止出现这种情况。。。但我不确定。
看起来您正在阅读shared\u x
,计算新的内容,然后写回shared\u x
。您写入共享的值似乎取决于您最初从中读取的值。
如果是这种情况,您在那里有一个依赖项,很可能不仅需要使读取原子化,还需要使“读取、计算、回写”的整个操作原子化。意思是,你需要同步它。比如互斥锁。
我之所以说“最有可能”,是因为我不能确定我是否不知道代码的实际功能。您需要分析在争用条件下发生的情况,即线程a写入shared_x
,而线程B当前正在基于shared_x
的旧值进行计算,然后将结果写回它。线程A写入的值将永远丢失。我不知道这对你来说是否有问题。只有你知道。如果争用条件正常,则不需要同步或使读取原子化。
如果您只想确保从shared_x
读取不会产生垃圾,并且不关心上面描述的竞争条件,那么答案是“很可能您不需要使读取原子化”而不是我复制
C语言中的原子性:神话还是现实
即使问题是C,C也是如此。
请注意,原子现在也在C标准中(C11),由提供
主要内容:常用的原子操作命令维护原子性的推荐方法是保留所有相关信息,并将这些信息使用嵌入式文档的形式更新到文档中,这将确保单个文档的所有更新都是原子的。假设我们已经创建了一个名为 productDetails 的集合,并在其中插入了一个文档,如下所示: 在上面的文档中,我们将购买产品的客户的信息嵌入到 product_bought_by 字段中。当有新客户购买该产品时,我们首先会使用 product_available 字段
原子操作 是个不可分割的操作。 在系统的所有线程中,你是不可能观察到原子操作完成了一半这种情况的; 它要么就是做了,要么就是没做,只有这两种可能。 如果从对象读取值的加载操作是 原子 的,而且对这个对象的所有修改操作也是 原子 的, 那么加载操作得到的值要么是对象的初始值,要么是某次修改操作存入的值。 另一方面,非原子操作可能会被另一个线程观察到只完成一半。 如果这个操作是一个存储操作,那么其他线
乐观锁与悲观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换。切换涉及到清空寄存器,缓存数据。然后重新加载新的thread所需数据。当一个线程被挂起时,加入到阻塞队列,在一定的时间或条件下,在通过notify(),notifyAll()唤醒回来。 在某个资源不可用的时候,就将
对于并发操作而言,原子操作是个非常现实的问题。典型的就是i 的问题。 当两个CPU同时对内存中的i进行读取,然后把加一之后的值放入内存中,可能两次i的结果,这个i只增加了一次。 如何保证多CPU对同一块内存的操作是原子的。 golang中sync/atomic就是做这个使用的。 具体的原子操作在不同的操作系统中实现是不同的。比如在Intel的CPU架构机器上,主要是使用总线锁的方式实现的。 大致的
主要内容:1 atomic的概述,2 原子更新单个变量,2.1 基本原子类,2.2 带版本号的原子类,3 原子更新数组,3.1 重要属性,3.2 重要方法,4 原子更新字段属性,5 原子类的加强,6 atomic的总结基于JDK1.8详细介绍了JUC下面的atomic子包中的大部分原子类的底层源码实现,比如AtomicInteger、AtomicIntegerArray、AtomicStampedReference等原子类源码。最后还介绍了JDK1.8对原子类的增强,比如LongAdder和Lo
启动C 20时,原子的操作有等待操作和通知操作。但我不知道它们到底是怎么工作的。cppreference说: 执行原子等待操作。表现为它重复执行以下步骤: 比较此的值表示形式- 这些函数保证仅在值发生更改时返回,即使底层实现错误地解除了阻塞。 我不太明白这两个部分是如何相互关联的。这是否意味着如果值没有更改,那么即使我使用了notify\u one()/方法,函数也不会返回?这意味着该操作在某种程