首页 \ 问答 \ 在C11中具有非原子的栅栏(Fences with non-atomics in C11)

在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 ints 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 an atomic_int even be the same size as an int, I can't use an atomic_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 changing ready to an _Atomic. (I could make ready a volatile, 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
更新时间:2023-08-07 11:08

最满意答案

系统需要保证在写入发生时,空间可用。 如果系统稍后将耗尽磁盘空间,则现在不能使分配失败。

这并不意味着写入磁盘; 页面预订仅仅是簿记。


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.
  • 不,超过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 ...

相关文章

更多

最新问答

更多
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)
  • 是否可以嵌套hazelcast IMaps?(Is it possible to nest hazelcast IMaps? And whick side effects can I expect? Is it a good Idea anyway?)
  • UIViewAnimationOptionRepeat在两个动画之间暂停(UIViewAnimationOptionRepeat pausing in between two animations)
  • 在x-kendo-template中使用Razor查询(Using Razor query within x-kendo-template)
  • 在BeautifulSoup中替换文本而不转义(Replace text without escaping in BeautifulSoup)
  • 如何在存根或模拟不存在的方法时配置Rspec以引发错误?(How can I configure Rspec to raise error when stubbing or mocking non-existing methods?)
  • asp用javascript(asp with javascript)
  • “%()s”在sql查询中的含义是什么?(What does “%()s” means in sql query?)
  • 如何为其编辑的内容提供自定义UITableViewCell上下文?(How to give a custom UITableViewCell context of what it is editing?)
  • c ++十进制到二进制,然后使用操作,然后回到十进制(c++ Decimal to binary, then use operation, then back to decimal)
  • 以编程方式创建视频?(Create videos programmatically?)
  • 无法在BeautifulSoup中正确解析数据(Unable to parse data correctly in BeautifulSoup)
  • webform和mvc的区别 知乎
  • 如何使用wadl2java生成REST服务模板,其中POST / PUT方法具有参数?(How do you generate REST service template with wadl2java where POST/PUT methods have parameters?)
  • 我无法理解我的travis构建有什么问题(I am having trouble understanding what is wrong with my travis build)
  • iOS9 Scope Bar出现在Search Bar后面或旁边(iOS9 Scope Bar appears either behind or beside Search Bar)
  • 为什么开机慢上面还显示;Inetrnet,Explorer
  • 有关调用远程WCF服务的超时问题(Timeout Question about Invoking a Remote WCF Service)