代码之家  ›  专栏  ›  技术社区  ›  theschmitzer

是C++的int和Atomic的读写吗?

  •  76
  • theschmitzer  · 技术社区  · 17 年前

    我有两个线程,一个更新一个int,另一个读取它。这是一个统计值,其中读和写的顺序不相关。

    我的问题是,我是否需要同步对此多字节值的访问?或者,换一种方式,写的一部分可以完成并被中断,然后读就发生了。

    例如,考虑一个值=0x000ffff,该值的递增值为0x00010000。

    有没有时间值看起来像0x0001ffff,我应该担心?当然,类型越大,发生这种事情的可能性就越大。

    我一直在同步这些类型的访问,但很好奇社区会怎么想。

    15 回复  |  直到 9 年前
        1
  •  44
  •   Adam Mitz    14 年前

    起初,人们可能认为本机大小的读写是原子的,但是有许多问题需要处理,包括处理器/核心之间的缓存一致性。在Windows和Linux上使用类似于interlocked*的原子操作。C++0x将有一个“原子”模板将它们封装在一个漂亮的跨平台接口中。目前,如果您使用的是平台抽象层,那么它可能提供这些功能。 ACE 是的,请参见类模板 ACE_Atomic_Op .

        2
  •  64
  •   ildjarn    10 年前

    孩子,真是个问题。答案是:

    是的,不,嗯,好吧,要看情况而定

    这都归结到系统的体系结构。在IA32上,正确对齐的地址将是原子操作。未对齐的写入可能是原子的,这取决于正在使用的缓存系统。如果内存位于单个一级缓存线内,那么它是原子的,否则它不是。CPU和RAM之间总线的宽度会影响原子性质:8086上正确对齐的16位写入是原子的,而8088上相同的写入并不是因为8088只有8位总线,而8086只有16位总线。

    此外,如果使用C/C++,不要忘记将共享值标记为易失性,否则优化器会认为变量永远不会在一个线程中更新。

        3
  •  11
  •   gabr    17 年前

    如果您正在读/写4字节的值,并且它在内存中是双字对齐的,并且您正在I32体系结构上运行,那么读和写是原子的。

        4
  •  8
  •   Anthony Williams    17 年前

    是的,您需要同步访问。在C++0x中,它将是一个数据竞争和未定义行为。对于POSIX线程,它已经是未定义的行为。

    在实践中,如果数据类型大于本机字大小,可能会得到错误的值。另外,由于优化移动读和/或写,另一个线程可能永远看不到写入的值。

        5
  •  3
  •   Jason Cohen    17 年前

    您必须进行同步,但在某些体系结构中,有有效的方法可以实现同步。

    最好的方法是使用子例程(可能隐藏在宏后面),这样就可以有条件地用特定于平台的实现替换实现。

    Linux内核已经有了一些这样的代码。

        6
  •  3
  •   Andrew Stein    17 年前

    在Windows上,互锁的***交换***添加保证是原子的。

        7
  •  1
  •   Tim Cooper    13 年前

    为了呼应楼上所有人所说的,语言pre-c++0x不能保证从多个线程访问共享内存。任何保证都取决于编译器。

        8
  •  1
  •   Jean Davy    12 年前

    绝对不! 来自我们最高C++权威的答案,M. Boost:
    Operations on "ordinary" variables are not guaranteed to be atomic.

        9
  •  0
  •   Leon Timmermans    17 年前

    不,他们不是(或者至少你不能假设他们是)。尽管如此,原子性地实现这一点还是有一些诀窍的,但它们通常不可移植(参见 Compare-and-swap )

        10
  •  0
  •   Community Mohan Dere    8 年前

    我同意很多,尤其是 Jason . 在Windows上,可能会使用InterlockedAdd及其朋友。

        11
  •  0
  •   JeffV    17 年前

    从上面提到的缓存问题中分配…

    如果将代码移植到寄存器较小的处理器上,那么它就不再是原子的了。

    在我看来,线程问题太棘手,无法冒险。

        12
  •  0
  •   sth    15 年前

    举个例子

    int x;
    x++;
    x=x+5;
    

    第一条语句被假定为原子语句,因为它转换为占用单个CPU周期的单个inc汇编指令。但是,第二个分配需要几个操作,因此显然不是原子操作。

    另一个,

    x=5;
    

    同样,您必须分解代码来看看这里到底发生了什么。

        13
  •  0
  •   siddhusingh    15 年前

    锝 我认为一旦你使用一个常量(比如6),指令就不会在一个机器周期内完成。 与x相比,尝试查看x+=6的指令集++

        14
  •  0
  •   etham    13 年前

    有些人认为,++C是原子的,但是他们关注生成的程序集。例如,使用“gcc-s”时:

    movl    cpt.1586(%rip), %eax
    addl    $1, %eax
    movl    %eax, cpt.1586(%rip)
    

    为了增加一个int,编译器首先将其加载到一个寄存器中,然后将其存储回内存中。这不是原子的。

        15
  •  -1
  •   Edward Howorka    15 年前

    唯一可移植的方法是为编译器使用在signal.h头文件中定义的sig_atomic_t类型。在大多数C和C++实现中,这是int。然后将变量声明为“易失性SiguAuthIcIt”。