Problems with non-atomic access example on GNU website

|▌冷眼眸甩不掉的悲伤 提交于 2021-01-29 01:31:43

问题


On the website of GNU there is a simple example available which is supposed to demonstrate the problems appearing with non-atomic access. The example contains a small mistake, they have forgotten #include <unistd.h>:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

struct two_words { int a, b; } memory;

static struct two_words zeros = { 0, 0 }, ones = { 1, 1 };

void handler(int signum)
{
   printf ("%d,%d\n", memory.a, memory.b);
   alarm (1);
}

int main (void)
{
   signal (SIGALRM, handler);
   memory = zeros;
   alarm (1);
   while (1)
     {
    memory = zeros;
    memory = ones;
     }
}

The idea is that the assignment memory = zeros; or the memory = ones; takes multiple cycles and thus the interrupt handler will be able to print "0 1" or "1 0" at some point in time.

However, interestingly for the x86-64 architecture, the assembly code produced by the gcc compiler looks as follows. It appears that the assignment is done within one single cycle by the movq instruction:

    .file   "interrupt_handler.c"
    .text
    .comm   memory,8,8
    .local  zeros
    .comm   zeros,8,8
    .data
    .align 8
    .type   ones, @object
    .size   ones, 8
ones:
    .long   1
    .long   1
    .section    .rodata
.LC0:
    .string "%d,%d\n"
    .text
    .globl  handler
    .type   handler, @function
handler:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    %edi, -4(%rbp)
    movl    4+memory(%rip), %edx
    movl    memory(%rip), %eax
    movl    %eax, %esi
    leaq    .LC0(%rip), %rdi
    movl    $0, %eax
    call    printf@PLT
    movl    $1, %edi
    call    alarm@PLT
    nop
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   handler, .-handler
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    leaq    handler(%rip), %rsi
    movl    $14, %edi
    call    signal@PLT
    movq    zeros(%rip), %rax
    movq    %rax, memory(%rip)
    movl    $1, %edi
    call    alarm@PLT
.L3:
    movq    zeros(%rip), %rax
    movq    %rax, memory(%rip)
    movq    ones(%rip), %rax
    movq    %rax, memory(%rip)
    jmp .L3
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 7.3.0-16ubuntu3) 7.3.0"
    .section    .note.GNU-stack,"",@progbits

Can someone explain how it is possible that two different assignments are done within a single cycle? Because I would think that the assignment of two different ints has to happen to two different pieces of memory, but somehow it seems over here that they are written to the same place.

This example changes when instead of int, I would use double. The while loop in assembly becomes:

.L3:
    movq    zeros(%rip), %rax
    movq    8+zeros(%rip), %rdx
    movq    %rax, memory(%rip)
    movq    %rdx, 8+memory(%rip)
    movq    ones(%rip), %rax
    movq    8+ones(%rip), %rdx
    movq    %rax, memory(%rip)
    movq    %rdx, 8+memory(%rip)
    jmp .L3

来源:https://stackoverflow.com/questions/52859599/problems-with-non-atomic-access-example-on-gnu-website

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!