在C11中具有非原子的栅栏(Fences with non-atomics in C11)
有没有办法使用栅栏来推断C11中非原子操作的行为? 具体来说,我想在某些字段需要为
int
以与旧接口兼容的情况下使代码安全,这些旧接口可能会读取和写入数据结构到文件或将它们作为系统调用参数传递。 因为没有要求atomic_int
甚至与int
大小相同,所以我不能使用atomic_int
。这是一个最小的工作示例,遗憾的是根据5.1.2.4第25节产生了未定义的行为,因为数据竞争
ready
:#include <stdatomic.h> #include <stdio.h> #include <threads.h> int ready; /* purposely NOT _Atomic */ int value; void p1() { value = 1; atomic_thread_fence(memory_order_release); ready = 1; } void p2(void *_ignored) { while (!ready) ; atomic_thread_fence(memory_order_acquire); printf("%d\n", value); } int main() { thrd_t t; thrd_create(&t, p2, NULL); p1(); thrd_join(&t, NULL); }
我的具体问题是,是否可以修复上述代码以保证打印
1
而不用ready
_Atomic
。 (我可以ready
一个volatile
,但是在规范中没有看到任何有助于此的建议。)一个相关的问题是,无论如何编写上面的代码是否安全,因为我的代码运行的任何机器都具有缓存一致性? 我知道当C11程序包含所谓的良性竞赛时, 很多 事情都会出错 ,所以我真的在寻找一个合理的编译器和架构可以对上面的代码做什么的细节,而不是关于数据竞争和未定义的一般警告行为。
Is there any way to use fences to reason about the behavior of non-atomic operations in C11? Specifically, I'd like to make code safe in situations where certain fields are required to be
int
s for compatibility with old interfaces that might, say, read and write data structures to files or pass them as system call arguments. As there's no requirement that anatomic_int
even be the same size as anint
, I can't use anatomic_int
.Here's a minimal working example that unfortunately produces undefined behavior according to section 5.1.2.4 paragraph 25, because of the data race on
ready
:#include <stdatomic.h> #include <stdio.h> #include <threads.h> int ready; /* purposely NOT _Atomic */ int value; void p1() { value = 1; atomic_thread_fence(memory_order_release); ready = 1; } void p2(void *_ignored) { while (!ready) ; atomic_thread_fence(memory_order_acquire); printf("%d\n", value); } int main() { thrd_t t; thrd_create(&t, p2, NULL); p1(); thrd_join(&t, NULL); }
My specific question is whether it's possible to fix the above code to guarantee printing
1
without changingready
to an_Atomic
. (I could makeready
avolatile
, but don't see any suggestion in the spec that this would help.)A related question is whether it's safe to write the above code anyway, because any machine my code will run on has cache coherence? I'm aware that many things go wrong when C11 programs contain so-called benign races, so I'm really looking for the specifics of what a plausible compiler and architecture could do to the above code rather than general warnings about data races and undefined behavior.
原文:https://stackoverflow.com/questions/42122610
最满意答案
系统需要保证在写入发生时,空间可用。 如果系统稍后将耗尽磁盘空间,则现在不能使分配失败。
这并不意味着写入磁盘; 页面预订仅仅是簿记。
The system needs the guarantee that when a write happens, space will be available. You can't fail an allocation now if the system will run out of diskspace later.
That doesn't mean the disk s written to; the page reservation is merely bookkeeping.
相关问答
更多-
有可能使用未记录的API。 sun.misc.Unsafe有一个方法pageSize() ,根据文档: 报告本地内存页面的大小(以字节为单位)。 这个值将永远是2的幂。 示例代码: import java.lang.reflect.Field; import sun.misc.Unsafe; public class PageInfo { public static void main(String... args) throws Exception { Fiel ...
-
如果上面的理解是正确的混淆,那就是我们对虚拟记忆缺乏了解。 你所说的理解是不对的,但你的困惑似乎确实在很大程度上与虚拟记忆有关。 虚拟内存系统的要点是允许每个进程访问整个地址空间(或多或少),就像它是唯一运行的进程一样,而不考虑可用的物理RAM量。 “虚拟”并不意味着“虚假”或任何此类事情 - 有一两个警告,如果程序分配了虚拟内存,那么它具有真正的存储空间。 “虚拟”部分与在与任何特定虚拟地址相关联的存储的任何给定时间处的实际位置有关。 通过将ELF与虚拟内存过于紧密地联系在一起,您似乎也会让自己感到困惑。 ...
-
大多数应用程序甚至无法知道它们是使用虚拟内存进行管理的,因为操作系统会对应用程序发出的每个内存请求执行地址转换。 除非您在非常低级别的环境中工作,否则这绝对是最好留给操作系统的任务(在这种情况下,您可能正在编写自己的操作系统)。 除了需要内核权限才能完成之外,您还需要注意不要破坏其他进程的内存。 操作系统是这种逻辑的最佳选择。 Most applications would not be able to even know that they are being managed using virtual ...
-
你可以在内存中映射文件,unix和windows系统都支持这个(但是使用不同的API)。 之后,您只需写入该内存位置,并在需要时进行同步。 You can memory map the file, both unix and windows system support this (but with different API). After that, you can simply write to that memory location, and do a sync when needed.
-
linux虚拟内存参数(linux virtual memory parameters)[2023-04-29]
不,超过dirty_bytes (或dirty_ratio )不会导致进程开始直接写入磁盘。 相反,当一个进程弄脏超过限制的页面时,该进程用于执行某些脏页面的同步写入 - 具体哪些仍然由通常的启发式决定。 它们可能不一定是最初被特定过程弄脏的页面。 实际上,进程看到它的写入(可能只是一个内存写入)暂停,直到发生一些写出。 你对dirty_background_*是正确的。 超出后台限制时,将启动异步写入,但允许用户空间进程继续。 No, exceeding dirty_bytes (or dirty_rat ... -
系统需要保证在写入发生时,空间可用。 如果系统稍后将耗尽磁盘空间,则现在不能使分配失败。 这并不意味着写入磁盘; 页面预订仅仅是簿记。 The system needs the guarantee that when a write happens, space will be available. You can't fail an allocation now if the system will run out of diskspace later. That doesn't mean the dis ...
-
为您的场景“制作”的数据结构是B树或其变体,如B +树 。 The data structure that is "made" for your scenario is B-tree or its variants, like B+ tree.
-
这与磁盘上的簇大小相同。 较大的页面数=>较低的开销(较小的页面表) 较小的页面=>较大的开销 较大的页面数=>更多的内存浪费和更多的磁盘读写页面 较小的页面=>减少内存浪费,减少分页读写磁盘 老年人说,页面大小往往比今天小得多(512字节是常见的)。 随着内存的增长,浪费的内存分页问题减少了,而开销问题(由于更多的页面)增加了。 因此我们有更大的页面大小。 一个字节的页面没有任何东西。 您必须以完整的磁盘块(通常为512字节或更大)写入磁盘。 分页单个字节将会非常慢。 现在添加页面保护和页面表。 使用单字 ...
-
不, Linux内核维护进程页表(但不是进程本身)。 进程只能看到虚拟内存通过其地址空间 。 进程使用一些系统调用 (例如mmap(2)或execve(2))来更改其地址空间。 物理地址和页表以及处理和管理MMU是内核的业务,它实际上为用户应用程序提供了一些“ 抽象机器 ”(具有虚拟地址空间,系统调用作为原子基本操作等)。 应用程序看不到原始(x86)硬件,而只看到内核给出的用户模式 。 某些硬件资源和指令不可用(它们仅在用户空间中运行)。 页表由内核管理,实际上各种进程可以使用不同的或有时相同的页表。 ( ...
-
页面可以同时在物理内存和虚拟内存中吗? 当您分页存储器块时,您需要空间用于其他内容,因此将它放在RAM和页面文件中是没有意义的。 如果我要求虚拟内存上的地址,它是否总会触发页面错误? 如果第一个问题是真的,那么它应该只在页面不在物理内存中时触发页面错误。 是对的吗? 恩,那就对了。 Pagefaults会导致中断。 如果在访问内存时总是遇到页面故障而不是只有很少的性能。 Can a page be at the same time in physical memory and in virtual memo ...