原子指令
原子指令是什么意思?
下面的内容如何变成原子的?
TestAndSet
int TestAndSet(int *x){
register int temp = *x;
*x = 1;
return temp;
}
从软件的角度来看,如果不想使用非阻塞同步原语,如何保证指令的原子性呢?是否只能在硬件上或可以使用某些汇编级指令优化?
What do you mean by Atomic instructions?
How does the following become Atomic?
TestAndSet
int TestAndSet(int *x){
register int temp = *x;
*x = 1;
return temp;
}
From a software perspective, if one does not want to use non-blocking synchronization primitives, how can one ensure Atomicity of instruction? is it possible only at Hardware or some assembly level directive optimization can be used?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
一些机器指令本质上是原子的 - 例如,在许多架构上,读取和写入正确对齐的本机处理器字大小的值是原子的。
这意味着硬件中断、其他处理器和超线程无法中断读取或存储以及将部分值读取或写入到同一位置。
更复杂的事情(例如原子地一起读写)可以通过显式原子机器指令(例如 x86 上的 LOCK CMPXCHG)来实现。
锁定和其他高级构造是基于这些原子原语构建的,它们通常仅保护单个处理器字。
一些聪明的并发算法可以仅使用指针的读取和写入来构建,例如在单个读取器和写入器之间共享的链接列表中,或者通过努力,多个读取器和写入器之间共享。
Some machine instructions are intrinsically atomic - for example, reading and writing properly aligned values of the native processor word size is atomic on many architectures.
This means that hardware interrupts, other processors and hyper-threads cannot interrupt the read or store and read or write a partial value to the same location.
More complicated things such as reading and writing together atomically can be achieved by explicit atomic machine instructions e.g. LOCK CMPXCHG on x86.
Locking and other high-level constructs are built on these atomic primitives, which typically only guard a single processor word.
Some clever concurrent algorithms can be built using just the reading and writing of pointers e.g. in linked lists shared between a single reader and writer, or with effort, multiple readers and writers.
以下是我对原子性的一些注释,可以帮助您理解其含义。这些注释来自最后列出的来源,如果您需要更彻底的解释而不是像我一样的点状项目符号,我建议您阅读其中的一些注释。有错误的地方请指出,以便我改正。
定义:
从来没有半途而废。
全部。
直接变异,没有“半途变异”值
示例 1:原子操作
考虑不同线程使用的以下整数:
<前><代码> int X = 2;
整数 Y = 1;
整数 Z = 0;
Z = X; //线程1
X=Y; //线程2
在上面的示例中,两个线程使用 X、Y 和 Z
示例 2:非原子操作:++/-- 操作< /strong>
考虑递增/递减表达式:
<前><代码>i++; //增量
我 - ; //递减
操作转换为:
示例 3 - 非原子操作:大于 4 字节的值
我们创建具有 MyLong 类型的特定值的字段:
<块引用>
我们在单独的线程中修改字段,没有线程安全:
<块引用>
<前><代码>X = Y; //线程1
Y=X; //线程2
在 .NET 中,复制值类型时,CLR 不会调用构造函数 - 它一次移动一个原子操作的字节
考虑以下执行操作顺序:
<块引用>
考虑
在 32 位操作系统上的多个线程上读取和写入大于 32 位的值,而不添加某种锁定以使操作原子化,可能会导致如上所述的数据损坏
处理器操作
在所有现代操作系统上处理器,您可以假设自然对齐的本机类型的读取和写入是原子的,只要:
语言差异< /strong>
C#
C++
Java
来源
http://www.evernote.com/shard /s10/sh/c2735e95-85ae-4d8c-a615-52aadc305335/99de177ac05dc8635fb42e4e6121f1d2
Below are some of my notes on Atomicity that may help you understand the meaning. The notes are from the sources listed at the end and I recommend reading some of them if you need a more thorough explanation rather than point-form bullets as I have. Please point out any errors so that I may correct them.
Definition :
never halfway done.
all.
mutated directly, with no "halfway mutated" values
Example 1 : Atomic Operations
Consider the following integers used by different threads :
In the above example, two threads make use of X, Y, and Z
Example 2 : Non-Atomic Operations : ++/-- Operations
Consider the increment/decrement expressions :
The operations translate to :
Example 3 - Non-Atomic Operations : Values greater than 4-Bytes
We create fields with specific values of type MyLong :
We modify our fields in separate threads without thread safety :
In .NET, when copying a value type, the CLR doesn't call a constructor - it moves the bytes one atomic operation at a time
Consider the following execution order of operations :
Reading and writing values greater than 32-bits on multiple threads on a 32-bit operating system without adding some sort of locking to make the operation atomic is likely to result in corrupt data as above
Processor Operations
On all modern processors, you can assume that reads and writes of naturally aligned native types are atomic as long as :
On x86 and X64 there is no guarantee that reads and writes larger than eight bytes are atomic
Language Differences
C#
C++
Java
Sources
http://www.evernote.com/shard/s10/sh/c2735e95-85ae-4d8c-a615-52aadc305335/99de177ac05dc8635fb42e4e6121f1d2
原子来自希腊语ἄτομος(atomos),意思是“不可分割”。 (注意:我不会说希腊语,所以也许它实际上是别的东西,但大多数说英语的人引用词源都是这样解释的。:-)
在计算中,这意味着操作,<我>发生了。在完成之前没有任何可见的中间状态。因此,如果您的 CPU 因服务硬件 (IRQ) 而中断,或者另一个 CPU 正在读取同一内存,则不会影响结果,并且这些其他操作将观察到它已完成或未启动。
举个例子......假设您想将变量设置为某项,但前提是之前尚未设置过该变量。您可能倾向于这样做:
但是如果并行运行怎么办?程序可能会获取
foo
,将其视为零,同时线程 2 出现并执行相同的操作并将值设置为某个值。回到原始线程,代码仍然认为 foo 为零,并且该变量被分配了两次。对于这样的情况,CPU 提供了一些指令,可以作为原子实体进行比较和条件赋值。因此,测试和设置、比较和交换以及加载链接/条件存储。您可以使用它们来实现锁(您的操作系统和 C 库已完成此操作。)或者您可以编写依赖原语来执行某些操作的一次性算法。 (这里有一些很酷的事情要做,但大多数凡人都会避免这样做,因为担心出错。)
Atomic comes from the Greek ἄτομος (atomos) which means "indivisible". (Caveat: I don't speak Greek, so maybe it's really something else, but most English speakers citing etymologies interpret it this way. :-)
In computing, this means that the operation, well, happens. There isn't any intermediate state that's visible before it completes. So if your CPU gets interrupted to service hardware (IRQ), or if another CPU is reading the same memory, it doesn't affect the result, and these other operations will observe it as either completed or not started.
As an example... let's say you wanted to set a variable to something, but only if it has not been set before. You might be inclined to do this:
But what if this is run in parallel? It could be that the program will fetch
foo
, see it as zero, meanwhile thread 2 comes along and does the same thing and sets the value to something. Back in the original thread, the code still thinksfoo
is zero, and the variable gets assigned twice.For cases like this, the CPU provides some instructions that can do the comparison and the conditional assignment as an atomic entity. Hence, test-and-set, compare-and-swap, and load-linked/store-conditional. You can use these to implement locks (your OS and your C library has done this.) Or you can write one-off algorithms that rely on the primitives to do something. (There's cool stuff to be done here, but most mere mortals avoid this for fear of getting it wrong.)
当您进行任何形式的包含共享资源的并行处理(包括不同的应用程序协作或共享数据)时,原子性是一个关键概念。
通过一个例子很好地说明了这个问题。假设您有两个程序想要创建一个文件,但前提是该文件尚不存在。这两个程序中的任何一个都可以在任何时间点创建该文件。
如果您这样做(我将使用 C,因为它是您的示例中的内容):
您无法确定其他程序在您的打开读取和打开写入之间没有创建该文件。
您无法自己完成此操作,您需要操作系统的帮助,通常为此目的提供同步原语,或者保证原子性的其他机制(例如,锁定操作是原子性的关系数据库,或较低级别的机制,如处理器“测试和设置”指令)。
Atomicity is a key concept when you have any form of parallel processing (including different applications cooperating or sharing data) that includes shared resources.
The problem is well illustrated with an example. Let's say you have two programs that want to create a file but only if the file doesn't already exists. Any of the two program can create the file at any point in time.
If you do (I'll use C since it's what's in your example):
you can't be sure that the other program hasn't created the file between your open for read and your open for write.
There's no way you can do this on your own, you need help from the operating system, that usually provide syncronization primitives for this purpose, or another mechanism that is guaranteed to be atomic (for example a relational database where the lock operation is atomic, or a lower level mechanism like processors "test and set" instructions).
原子性只能由操作系统来保证。操作系统使用底层处理器功能来实现此目的。
因此创建自己的 testandset 函数是不可能的。 (虽然我不确定是否可以使用内联 asm 片段,并直接使用 testandset 助记符(可能该语句只能使用操作系统权限来完成))
编辑:
根据本文下面的评论,可以直接使用 ASM 指令创建自己的“bittestandset”函数(在 intel x86 上)。然而,这些技巧是否也适用于其他处理器尚不清楚。
我坚持我的观点:如果你想做一些大气的事情,请使用操作系统功能,而不是自己做
Atomicity can only be guaranteed by the OS. The OS uses the underlying processor features to achieve this.
So creating your own testandset function is impossible. (Although I'm not sure if one could use an inline asm snippet, and use the testandset mnemonic directly (Could be that this statement can only be done with OS priviliges))
EDIT:
According to the comments below this post, making your own 'bittestandset' function using an ASM directive directly is possible (on intel x86). However, if these tricks also work on other processors is not clear.
I stand by my point: if You want to do atmoic things, use the OS functions and don't do it yourself