Быстрый вопрос я задавался вопросом о в течение некоторого времени; Делает ЦП, присваивают значения атомарно, или, это поразрядно (скажите, например, что целое число на 32 бита).
Если это является поразрядным, другой мог бы распараллелить доступ к этому точному местоположению, получают "часть" присвоенного будущим образом значения?
Думайте об этом:
У меня есть два потока, и одна общая "неподписанная международная" переменная (назовите это "g_uiVal").
Оба цикла потоков.
На печатает "g_uiVal" с printf (" %u\n", g_uiVal).
Вторые просто увеличивают это число.
Печать распараллелит, когда-нибудь печатают что-то, что является полностью не или часть значения "g_uiVal"?
В коде:
unsigned int g_uiVal;
void thread_writer()
{
g_uiVal++;
}
void thread_reader()
{
while(1)
printf("%u\n", g_uiVal);
}
Зависит от ширины шины ЦП и памяти. В контексте ПК, с чем-либо, кроме действительно древнего ЦП, доступ до 32-битного доступа является атомарным; 64-битные обращения могут быть, а могут и не быть. Во встроенном пространстве многие (большинство?) Процессоров имеют ширину 32 бита, и нет возможности для чего-то более широкого, поэтому ваш int64_t
гарантированно будет неатомарным.
Я считаю, что единственный правильный ответ - «это зависит от обстоятельств». О чем вы спросите?
Ну, для начала, какой процессор. Но также некоторые процессоры являются атомарными для записи значений ширины слова, но только после выравнивания. Это не то, что вы можете гарантировать на уровне языка C.
Многие компиляторы предлагают «встроенные функции» для выполнения правильных атомарных операций. Это расширения, которые действуют как функции, но генерируют правильный код для вашей целевой архитектуры, чтобы получить необходимые атомарные операции. Например: http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html
В своем вопросе вы сказали «бит за битом». Я не думаю, что какая-либо архитектура выполняет операции понемногу, за исключением некоторых специализированных шин последовательного протокола. Стандартные операции чтения / записи в память выполняются с 8, 16, 32 или 64 битами гранулярности. Итак, ВОЗМОЖНО, что операция в вашем примере является атомарной.
Однако ответ сильно зависит от платформы.
ОЧЕНЬ ВОЗМОЖНО, что вы увидите поврежденное или неожиданное значение, используя опубликованный вами пример кода.
Ваша платформа, вероятно, предоставляет некоторый метод выполнения атомарных операций. В случае платформы Windows это осуществляется через взаимосвязанные функции . В случае Linux / Unix посмотрите на тип atomic_t .
Не забывайте, что компилятор предполагает однопоточность при оптимизации, и все это может просто исчезнуть.
Чтобы добавить к тому, что было сказано до сих пор - еще одной потенциальной проблемой является кэширование. Процессоры обычно работают с локальным (на матрице) кэшем памяти, который может быть или не быть немедленно сброшен обратно в основную память. Если в системе более одного процессора, возможно, что другой процессор не увидит изменений в течение некоторого времени после того, как их сделал изменяющий процессор - если только не существует команды синхронизации, сообщающей всем процессорам, что они должны синхронизировать свои внутренние кэши. Как вы можете себе представить, такая синхронизация может значительно замедлить обработку.
Учитывая современные микропроцессоры (и игнорируя микроконтроллеры), 32-битное присвоение является атомарным, а не побитовым.
Однако теперь полностью вне темы вашего вопроса ... поток печати все еще может печатать что-то, чего не ожидалось из-за отсутствия синхронизации в этом примере, конечно, из-за переупорядочения инструкций и нескольких ядер, каждое со своими собственными копия g_uiVal в их кешах.
POSIX определяет специальный тип sig_atomic_t
, который гарантирует, что записи в него являются атомарными по отношению к сигналам, что сделает его также атомарным с точки зрения других потоков, таких как ты хочешь. Они специально не определяют атомарный межпотоковый тип, подобный этому, поскольку ожидается, что обмен потоками будет осуществляться через мьютексы или другие примитивы синхронизации.