2016-06-23 2 views
-3

Я хочу знать, как побитовый оператор смены "<<" и ">>" реализован на языке. Это атомный или нет? Сдвигает ли все слово сразу или перемещает каждый бит один за другим.Как оператор битового сдвига реализован в C. Является ли он атомарным?

Существуют ли зависимости от компилятора, операционной системы или компьютерной архитектуры?

В стандарте C определяется, как будет выполняться оператор сдвига?

Пример:

скажем две нити получают доступ к данным. один из них изменяет его, сдвигая 3 бита. так делает это 3-битное смещение атомной операции или нет? следует ли использовать блокировки для обработки этой модификации?

РЕДАКТИРОВАТЬ: Это всего лишь оператор смены, без инструкции по хранению. данные уже находятся в памяти, поэтому нет загрузки. Мой процессор: Powerpc MPC8569, архитектура ядра e600.

+2

Если процессор не имеет инструкции с несколькими бит-сдвигами, то он не может. –

+3

Как вы могли бы рассказать? –

+2

Скомпилируйте файл для нужной арки, разоберите и найдите инструкцию, с которой она собрана. И есть ваш ответ, для этого комбо-компилятора. – Shark

ответ

0

Это зависит от того, какой стандарт вы говорите.

AFAIU, только атомарные операции (в явном виде определяются как атомные) в С11 являются те, связанными с <stdatomic.h>

Вы можете представить себе процессор Терагерцевого с 4 битами АЛУ; даже простое дополнение int32_t не будет атомарным.

+0

Поскольку старые версии даже не охватывают эту тему, она может относиться только к C11 в терминах семантики стандарта. – Olaf

5

C гарантирует только атомный доступ для переменных типа _Atomic, которые были введены в C11.

Для всех других ситуаций никогда не существует никаких гарантий атомного доступа. Вам нужно будет разобрать код C, чтобы узнать, сколько команд ассемблера он сгенерировал. Как правило, одна инструкция ассемблера всегда атомарна.

Но ваш вопрос не имеет особого смысла, потому что контекста нет. Куда бы произошел сдвиг? Вы планируете хранить его где-нибудь? Тогда это две операции: смена и сохранение. Возможно также и нагрузка. Если вы пишете алгоритм, который сам по себе не является атомарным, как вы ожидаете, что компилятор волшебным образом сделает его атомарным для вас?

+0

Извините за то, что вы так абстрактны, мой вопрос касается только оператора сдвига. –

+0

Астрономические операции @saurabhagarwal связаны с чтением и записью. Смещение только дает результат, не записывая его нигде, так как здесь есть ? –

+0

, скажем, два потока получают доступ к данным. один из них изменяет его, сдвигая 3 бита. так что это 3-битный сдвиг атомной операции или нет? должен ли я использовать блокировки для обработки этой модификации. –

3

Это зависит от используемого вами процессора.

Если присутствует инструкция для побитового сдвига, которая присутствует на большинстве ядер x86 и 16-разрядных и 32-разрядных микроконтроллерах, то она является атомарной.

Если, однако, у вас есть 8-разрядный микроконтроллер без инструкции по сдвигу бит или вы пытаетесь сдвинуть бит большого значения (например, 64 бит или 128 бит), то в инструкции может потребоваться довольно много кода.

+0

Все процессоры имеют инструкции по быстрой передаче. Не обязательно полный набор, но все же. Наличие инструкции не означает, что она является атомарной. – Olaf

+0

Нет, родные переменные x86 с операндами памяти не являются атомарными, и я думаю, что это верно в отношении большинства современных процессоров. –

-2

Обычно это должно быть SHLD/SHRD - двойной точности сдвига (386+) https://web.itu.edu.tr/kesgin/mul06/intel/instr/shld_shrd.html

Я думаю, что это атомная, потому что это одна команда. В противном случае вы можете использовать атомный или volatile, если c поддерживает его, C++ 11 поддерживает его.

+0

Отдельные инструкции не означают, что они являются атомарными. Даже если они предназначены для одного кода, они не в смысле С. – Olaf

0

Я написал две программы

#include<stdio.h> 
    int main() 
    { 
    int i = 5; 
    return 0; 
    } 

Его ассемблерный код, сгенерированный для PowerPC архитектуры код 1

.file "hello.c" 
    .section ".text" 
    .align 2 
    .globl main 
    .type main, @function 
main: 
    stwu 1,-32(1) 
    stw 31,28(1) 
    mr 31,1 
    li 0,5 
    stw 0,8(31) 
    li 0,0 
    mr 3,0 
    lwz 11,0(1) 
    lwz 31,-4(11) 
    mr 1,11 
    blr 
    .size main, .-main 
    .ident "GCC: (GNU) 4.2.2" 
    .section .note.GNU-stack,"",@progbits 

Второй код

#include<stdio.h> 
    int main() 
    { 
    int i = 5; 
    i = i<<1; 
    return 0; 
    } 

Моя сборка код, сгенерированный для PowerPC архитектуры кода 2 -

 .file "hello.c" 
     .section ".text" 
     .align 2 
     .globl main 
     .type main, @function 
    main: 
     stwu 1,-32(1) 
     stw 31,28(1) 
     mr 31,1 
     li 0,5 
     stw 0,8(31) 
     lwz 0,8(31) // extra 
     slwi 0,0,1 // extra 
     stw 0,8(31) // extra 
     li 0,0 
     mr 3,0 
     lwz 11,0(1) 
     lwz 31,-4(11) 
     mr 1,11 
     blr 
     .size main, .-main 
     .ident "GCC: (GNU) 4.2.2" 
     .section .note.GNU-stack,"",@progbits 

Вы видите, есть три дополнительные Instruction, поэтому операция не является атомарной

Я также скомпилирован это на i7 ПК Intel. Вот результаты:

ассемблерный код генерируется для первого кода: код

.file "hello.c" 
    .text 
    .globl main 
    .type main, @function 
main: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movl $5, -4(%rbp) 
    movl $0, %eax 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size main, .-main 
    .ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4" 
    .section .note.GNU-stack,"",@progbits 

Сборка Генерация кода 2:

.file "hello.c" 
    .text 
    .globl main 
    .type main, @function 
main: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movl $5, -4(%rbp) 
    sall -4(%rbp) // only one extra instruction 
    movl $0, %eax 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size main, .-main 
    .ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4" 
    .section .note.GNU-stack,"",@progbits 

Итак, я понимаю, что, ответ зависит от архитектуры мы используются.

+0

Вы просто укажите очевидное. Но это зависит не только от настроек команд процессора и адресации. Опираясь на компилятор, генерирующий конкретный код, приглашается на катастрофу. – Olaf

+1

PowerPC, как и любая архитектура RISC, использует дизайн магазина нагрузки. Он не имеет инструкций, которые могут работать непосредственно в памяти. Он должен загрузить значение из памяти, работать с ним, а затем сохранить его обратно. x86, однако, * может * работать непосредственно с значениями в памяти - по крайней мере, для этого есть одна команда. Но это не означает, что операция является атомарной. Типы инструкций, содержащих операнды памяти, разделяются на несколько микроопераций в процессоре. Одна инструкция не означает, что что-то является атомарным, а также несколько инструкций подразумевают, что это не так. –

+0

@CodyGray: Кроме того, компилятор может выбрать загрузку результата или источника для регистрации для оптимизации и т. Д. – Olaf

Смежные вопросы