gpt4 book ai didi

c - 通过_Atomic指针进行的非原子结构修改是否会产生数据争用?

转载 作者:行者123 更新时间:2023-12-03 12:54:07 24 4
gpt4 key购买 nike

我试图了解C11内存模型的工作原理,并编写了两个函数,其中包含conflict的表达式(就5.1.2.4(p4)而言):

struct my_struct{
uint64_t first;
int64_t second;
} * _Atomic instance;

void* set_first(void *ignored){
uint64_t i = 0;
while(1){
struct my_struct *ms = atomic_load_explicit(&instance, memory_order_acquire);
ms -> first = i++;
atomic_store_explicit(&instance, ms, memory_order_release);
sleep(1);
}
}

void* print_first(void *ignored){
while(1){
struct my_struct *ms = atomic_load_explicit(&instance, memory_order_acquire);
uint64_t current = ms -> first;
char buf[100];
memset(buf, '\0', sizeof(buf));
sprintf(buf, "%" PRIu64 "\n", current);
fputs_unlocked(buf, stdout);
sleep(2);
}
}

和主要功能:
int main(void){
struct my_struct tmp = {.first = 0, .second = 0};
atomic_init(&instance, &tmp);
printf("main\n");
pthread_t set_thread;
pthread_create(&set_thread, NULL, &set_first, NULL);

pthread_t print_thread;
pthread_create(&print_thread, NULL, &print_first, NULL);
while(1){
sleep(100);
}
}

因此,我试图证明该程序是否不包含任何数据争用。这是我的想法:
  • 我们知道原子对象上的释放操作与对象上的获取操作同步。因此,atomic_store_explicit(&instance, ms, memory_order_release);中的set_first atomic_load_explicit(&instance, memory_order_acquire)中的 print_first同步。
  • 由于ms -> first = i++函数中的副作用set_first出现在程序文本中的atomic_store_explicit(&instance, ms, memory_order_release);之前,所以我认为它是序列化的-在之前(这是我不确定的,找不到任何规范性引用)。
  • 组合项目符号1.2.意味着ms -> first = i++ 线程间发生在 atomic_load_explicit(&instance, memory_order_acquire);之前,因此它们在中发生在关系之前。
  • 应用数据争用定义,我们得出结论,将uint64_t current = ms -> first;函数中的print_firstms -> first = i++;函数中的set_first限制 Action 不会产生数据争用。

  • 因此,行为似乎是明确定义的。

    值得怀疑的是, ms -> first = i++; atomic_store_explicit(&instance, ms, memory_order_release);之前排序,因为它们在程序文本中一个接一个地出现。

    是正确的还是程序包含数据争用?

    最佳答案

    通过non-_Atomic指针修改非原子对象本身并不是数据争用UB。 (例如,您可以使用一种执行int *p = shared_ptr++;的算法,以使每个线程在非原子数组中抓取自己的插槽。)

    但是在这种情况下,您有一个明确的UB案例,因为您有2个线程访问main的tmp.first,并且它们都不都是读取的。

    带有mo_release的商店在任何先前的商店(和装载)之后(包括像ms->first = ...这样的非原子性商店)都被排序。这就是发行商店与放松之间的关系。

    但是推理的缺陷在于步骤1:atomic_store_explicit(&instance, ms, memory_order_release)中的set_first 仅与获取负载并显示存储的值同步! 不必神奇地等待尚未发生的发布存储,就可以获取其他线程中的加载。可以保证的是,如果/当您确实加载发行版store1存储的值时,您还可以从该线程中看到所有较早的内容。

    如果获取负载发生在发布存储之前(按全局顺序,如果有的话),那么就没有同步。

    这两个线程中的acquire-load可以同时发生,然后狐狸出现在鸡舍中:ms -> first = i++;uint64_t current = ms -> first;在没有同步的情况下运行。

    编写线程稍后将进行释放存储以将相同的值存储回instance中是完全不相关的。

    脚注1:
    (标准中的“发布顺序”语言将其扩展到查看RMW操作的结果,该操作修改了初始发布存储的结果,依此类推。)

    就其他线程而言,atomic_load_explicit中的set_first基本上是无关紧要的。您也可以将其从环路中吊起。

    关于c - 通过_Atomic指针进行的非原子结构修改是否会产生数据争用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55663398/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com