当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?
最近一个问题的 OP添加了一条评论,链接了一篇题为C11 内存模型中的通用编译器优化无效以及我们可以做些什么的论文,这显然是在 POPL 2015 上提出的。除其他外,它声称展示了几个从所谓的“C11 内存模型”的规范中得出的意外和违反直觉的结论,我认为主要由C11 语言规范第 5.1.2.4 节的规定组成。
这篇论文有点冗长,但出于这个问题的目的,我将重点放在第二页上对“SEQ”方案的讨论。这涉及一个多线程程序,其中...
a是非原子的(例如, an int),x并且y是原子的(例如,_Atomic int),并且a, x, 和y所有最初都有价值0,...然后发生以下情况(从伪代码音译):
主题 1
a = 1;
Run Code Online (Sandbox Code Playgroud)
主题 2
if (atomic_load_explicit(&x, memory_order_relaxed))
if (a)
atomic_store_explicit(&y, 1, memory_order_relaxed);
Run Code Online (Sandbox Code Playgroud)
主题 3
if (atomic_load_explicit(&y, memory_order_relaxed))
atomic_store_explicit(&x, 1, memory_order_relaxed);
Run Code Online (Sandbox Code Playgroud)
该论文提出了这样的论点:
首先,请注意没有发生负载的执行(第 2 节术语中的一致执行)
a。我们通过矛盾来证明这一点。假设有一个执行,其中a发生了负载。在这样的执行中, 的加载a只能返回0( 的初始值a),因为存储a=1 …
即使在阅读了相当多的严格别名规则后,我仍然感到困惑.据我所知,不可能实现遵循这些规则的合理的内存分配器,因为malloc永远不能重用释放的内存,因为内存可以用于在每次分配时存储不同的类型.
显然这不可能是正确的.我错过了什么?如何实现遵循严格别名的分配器(或内存池)?
谢谢.
编辑:让我用一个愚蠢的简单例子来澄清我的问题:
// s == 0 frees the pool
void *my_custom_allocator(size_t s) {
static void *pool = malloc(1000);
static int in_use = FALSE;
if( in_use || s > 1000 ) return NULL;
if( s == 0 ) {
in_use = FALSE;
return NULL;
}
in_use = TRUE;
return pool;
}
main() {
int *i = my_custom_allocator(sizeof(int));
//use int
my_custom_allocator(0);
float *f = my_custom_allocator(sizeof(float)); //not allowed...
}
Run Code Online (Sandbox Code Playgroud)