2015-08-30 3 views
0

Рассмотрим следующий фрагмент кода.Возможно ли прервать оценку выражения

#‎include‬ <stdio.h> 

void f(int *x, int *y) 
{ 
    (*x)++; 
    (*y)++; 
} 

int main() 
{ 
    int x=5, y=5; 

    f(&x, &y); 

return 0; 
} 

Я знаю, что функция f не является реентерабельной. Одна из глупых вещей, о которых я думаю, заключается в том, чтобы делать (* x) ++ + (* y) ++ в одной строке и отбрасывать сумму. Интересно, что для оценки этого выражения будут созданы несколько инструкций по сборке. Будет ли прерывание осуществляться между оценкой выражения?

+2

Что вы подразумеваете под «прерыванием»? Не могли бы вы рассказать? В чем проблема, которую вы пытаетесь решить? –

+0

Да, может. Но, пожалуйста, ради любви к программированию Богов, пожалуйста, не делайте того, что вы предложили. Гораздо лучше написать четкий код, чем «умный» код. – kaylum

+0

Спасибо Алан Ау. Я знаю, что глупо делать. Какая операция гарантированно будет атомарной в C? Я думаю, что это отдельный вопрос, но для поддержания контекста, который я задаю здесь. – user902384

ответ

1

Вы не получите ничего атомное с этим ...

c.o:  file format elf64-x86-64 


Disassembly of section .text: 

0000000000000000 <f>: 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: 48 89 7d f8    mov %rdi,-0x8(%rbp) 
    8: 48 89 75 f0    mov %rsi,-0x10(%rbp) 
    c: 48 8b 45 f8    mov -0x8(%rbp),%rax 
    10: 8b 00     mov (%rax),%eax 
    12: 8d 50 01    lea 0x1(%rax),%edx 
    15: 48 8b 45 f8    mov -0x8(%rbp),%rax 
    19: 89 10     mov %edx,(%rax) 
    1b: 48 8b 45 f0    mov -0x10(%rbp),%rax 
    1f: 8b 00     mov (%rax),%eax 
    21: 8d 50 01    lea 0x1(%rax),%edx 
    24: 48 8b 45 f0    mov -0x10(%rbp),%rax 
    28: 89 10     mov %edx,(%rax) 
    2a: 5d      pop %rbp 
    2b: c3      retq 

И это становится намного лучше с -O2, но все-таки это не атомная.

c.o:  file format elf64-x86-64 


Disassembly of section .text: 

0000000000000000 <f>: 
    0: 83 07 01    addl $0x1,(%rdi) 
    3: 83 06 01    addl $0x1,(%rsi) 
    6: c3      retq 

И, по крайней мере для GCC, то точно такой же код генерируется для (*x)++ + (*y++). В любом случае, можете ли вы немного подробнее рассказать о своем вопросе? Вы слишком широкие, и этот код is реентерант до тех пор, пока x и y не совпадают на разных позициях. В противном случае вы должны дать нам более подробную информацию о том, что вы намереваетесь.

Редактировать: Это (видимо, если нет какой-то скрытой черной магии ...) невозможно сделать такую ​​вещь атомарно на архитектуре x86 (-64). Во всяком случае, он не переносится, чтобы рассматривать операцию «атомная», если она выполняется в одной команде. Это характерно для процессоров x86 (-64).

+0

Нет функции f в оригинальной форме не является реентерабельной. Если прерывание подается после приращения x, то y не будет увеличено. Другой вызов f из main нарушен. – user902384

+0

@ user902384: It * is * reentrant, если он не вызывается с тем же аргументом (-ами) другим потоком. И в чем проблема с 'y' не увеличиваться сразу? После возобновления работы ОС это будет; никакого «возмущения» не происходит. – 3442

+0

@ user902384: p.d: Прочитайте [this] (https://en.wikipedia.org/wiki/Reentrancy_ (вычисления)), чтобы быть уверенным, что у нас есть то же определение «reentrancy». – 3442