如何将非原子操作转换为原子操作
我正在尝试了解原子和非原子操作。关于操作系统以及 C。 根据维基百科页面此处
考虑一个不同进程可以递增的简单计数器。< br> 非原子
简单的非原子实现:
读取内存位置中的值;
值加一;
将新值写回内存位置。
现在,假设两个进程正在运行并递增单个共享内存位置:
第一个进程读取内存位置中的值;
第一个过程将值加一;
但在它将新值写回内存位置之前,它被挂起,并且允许第二个进程运行:
第二个进程读取内存位置中的值,与第一个进程读取的值相同;
第二个进程将值加一;
第二个进程将新值写入内存位置。
如何使上述操作成为原子操作。 我对原子操作的理解是,任何不间断执行的事情都是原子的。 例如,
int b=1000;
b+=1000;
根据我的理解,应该是一个原子操作,因为这两条指令都在没有中断的情况下执行,但我从某人那里了解到,在 C 中没有什么称为原子操作,所以上面的两条语句都是非原子的。 所以我想了解的是编程语言与操作系统的原子性有何不同?
I am trying to understand atomic and non atomic operations.With respect to Operating System and also with respect to C.
As per the wikipedia page here
Consider a simple counter which different processes can increment.
Non-atomic
The naive, non-atomic implementation:
reads the value in the memory location;
adds one to the value;
writes the new value back into the memory location.
Now, imagine two processes are running incrementing a single, shared memory location:
the first process reads the value in memory location;
the first process adds one to the value;
but before it can write the new value back to the memory location it is suspended, and the second process is allowed to run:
the second process reads the value in memory location, the same value that the first process read;
the second process adds one to the value;
the second process writes the new value into the memory location.
How can the above operation be made an atmoic operation.
My understanding of atomic operation is that any thing which executes without interruption is atomic.
So for example
int b=1000;
b+=1000;
Should be an atomic operation as per my understanding because both the instructions executed without an interruption,how ever I learned from some one that in C there is nothing known as atomic operation so above both statements are non atomic.
So what I want to understand is what is atomicity is different when it comes to programming languages than the Operating Systems?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
C99 没有任何方法使变量相对于其他线程具有原子性。 C99没有多执行线程的概念。因此,您需要使用特定于编译器的扩展和/或 CPU 级指令来实现原子性。
下一个 C 标准(目前称为 C1x)将包含原子操作。
即使如此,仅仅原子性也只能保证操作是原子的,并不能保证该操作何时对其他 CPU 可见。为了实现可见性保证,在 C99 中,您需要研究 CPU 的内存模型,并可能使用一种称为栅栏或内存屏障的特殊 CPU 指令。您还需要使用一些特定于编译器的编译器屏障告诉编译器这一点。 C1x 定义了多种内存排序,当您使用原子操作时,您可以决定使用哪种内存排序。
一些例子:
所有这些都像看起来一样复杂,所以你通常应该坚持使用互斥体,这会让事情变得更容易。
C99 doesn't have any way to make variables atomic with respect to other threads. C99 has no concept of multiple threads of execution. Thus, you need to use compiler-specific extensions, and/or CPU-level instructions to achieve atomicity.
The next C standard, currently known as C1x, will include atomic operations.
Even then, mere atomicity just guarantees that an operation is atomic, it doesn't guarantee when that operation becomes visible to other CPUs. To achieve visibility guarantees, in C99 you would need to study your CPU's memory model, and possibly use a special kind of CPU instructions known as fences or memory barriers. You also need to tell the compiler about it, using some compiler-specific compiler barrier. C1x defines several memory orderings, and when you use an atomic operation you can decide which memory ordering to use.
Some examples:
All of this is as complex as it seems, so you should normally stick to mutexes, which makes things easier.
在指令级别变成多个语句。至少,准备一个寄存器或存储器,分配1000,然后获取该寄存器/存储器的内容,将内容加1000,并将新值(2000)重新分配给该寄存器。如果没有锁定,操作系统可以在该操作中的任何时刻挂起进程/线程。此外,在多进程系统上,当您的操作正在进行时,不同的处理器可以访问该内存(在这种情况下不是寄存器)。
当您锁定时(这就是如何使其原子化),您在某种程度上通知操作系统不能挂起此进程/线程,并且该内存不应被其他进程访问。
现在,上面的代码可能会被编译器优化为将 2000 简单分配给 b 的内存位置,但出于本答案的目的,我忽略了这一点。
gets turned into multiple statements at the instruction level. At the very least, preparing a register or memory, assigning 1000, then getting the contents of that register/memory, adding 1000 to the contents, and re-assigning the new value (2000) to that register. Without locking, the OS can suspend the process/thread at any point in that operation. In addition, on multiproc systems, a different processor could access that memory (wouldn't be a register in this case) while your operation is in progress.
When you take a lock out (which is how you would make this atomic), you are, in part, informing the OS that it is not ok to suspend this process/thread, and that this memory should not be accessed by other processes.
Now the above code would probably be optimized by the compiler to a simple assignment of 2000 to the memory location for b, but I'm ignoring that for the purposes of this answer.
b+=1000
在我所知道的所有系统上都被编译为多条指令。因此它不是原子的。即使
b=1000
也可以是非原子的,尽管您必须努力构建一个非原子的情况。事实上,C 没有线程的概念,因此 C 中没有什么是原子的。您需要依赖编译器和工具的实现特定细节。
b+=1000
is compiled, on all systems that I know, to multiple instructions. Thus it is not atomic.Even
b=1000
can be non atomic although you have to work hard to construct a situation where it is not atomic.In fact C has no concept of threads and so there is nothing that is atomic in C. You need to rely on implementation specific details of your compiler and tools.
上面的语句是非原子的,因为它变成了一条移动指令,将 b 加载到寄存器中(如果不是),然后向其添加 1000,然后将其存储回内存中。许多指令集允许通过原子增量实现原子性,最简单的是 x86 with lock addl dest, src;其他一些指令集使用 cmpxchg 来达到相同的结果。
The above statements are non atomic because it becomes a move instruction to load b into a register (if it isnt) then add 1000 to it and the store back into memory. Many instruction sets allow for atomicity through atomic increment easiest being x86 with lock addl dest, src; some other instruction sets use cmpxchg to achieve the same result.
这个问题我有点困惑。你到底是什么意思? prog 中的原子性概念是相同的。语言和操作系统。
关于原子性和语言,例如,这里有一个关于 JAVA 原子性的链接,可能会给您带来不同的视角: Java 中哪些操作被视为原子操作?
I'm a bit confused by this question. What do you mean exactly? The atomicity concept is the same both in prog. languages and OS.
Regarding atomicity and language, here is for example a link about atomicity in JAVA, that might give you a different perspective: What operations in Java are considered atomic?