Есть ли способ сделать функцию атомной В C?

есть ли способ сделать функцию атома в с.

Я не ищу портативное решение.(платформы ищут-Win, Linux)

7 ответов


может быть.

это полностью зависит от вашего определения "атомарного".

  • в одном ядре, глубоко врезанный среде без операционной системы, как правило, можно отключить и включить прерывания. Это можно использовать, чтобы разрешить функции быть атомарными по отношению к коду обработчика прерываний. Но если у вас есть шина multi-master, движок DMA или другое аппаратное устройство, которое может записывать память независимо, то даже маскирующие прерывания могут не обеспечить достаточно сильная гарантия в некоторых обстоятельствах.

  • в среде RTOS (операционная система реального времени) ядро ОС обычно предоставляет примитивы синхронизации низкого уровня, такие как критические разделы. Критический раздел-это блок кода, который ведет себя "по существу" атомарно, по крайней мере, по отношению ко всем другим критическим разделам. Обычно это имеет основополагающее значение для реализации ОС других примитивов синхронизации.

  • в многоядерных среда, примитив низкого уровня, называемый spinlock, часто доступен. Он используется для защиты от входа в блок кода, который должен быть атомарным по отношению к другим пользователям того же объекта spinlock, и работает, блокируя ожидающее ядро процессора в узком цикле, пока блокировка не будет освобождена (отсюда и название).

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

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


если вы хотите убедиться, что ваша функция не будет прерван сигналом, использовать sigprocmask() маскировать и демаскировать сигналы, хотя некоторые сигналы не могут быть заблокированы (например,SIGKILL) и поведение для блокировки некоторых сигналов (например,SIGSEGV) неопределено.

посмотреть man sigprocmask для сведения.


Не переносимо, по крайней мере. Для некоторых систем вы, вероятно, можете приблизиться к нему, делая такие вещи, как поворот прерываний машины, чтобы предотвратить упреждение ядра вашей функции. Но это будет очень сложно, особенно для не встроенных систем.


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


определите, что вы подразумеваете под 'atomic."Вы имеете в виду "атомарный" в том смысле, что никакой другой процесс или поток не будет выбран для планирования при запуске вашей функции? Или вы имеете в виду, что любые общие объекты, на которые ссылается ваша функция, не будут изменены другими потоками во время выполнения функции?

для первого вы не можете контролировать это из пользовательского пространства. Если вы находитесь на машине с одним процессором, вы можете возможно атомарность гарантии путем поднимать ваш процесс приоритет наивысшему возможному приоритету (от userspace). Но даже тогда это не гарантируется, потому что ваш алгоритм планирования все еще может позволить запустить другой процесс. Единственный надежный способ сделать это-из операционной системы. Для машины с одним процессором вы бы отключили прерывания. Для многоядерной машины вам нужно будет заблокировать шину и дождаться, пока все процессы, запущенные на других процессорах, будут сняты.

вопрос тут: Почему вы хотите, чтобы гарантировать атомарность? В общем, требование, что только ваш процесс может быть запущен, а не другие, не должно существовать в пространстве пользователей. Если вы хотите убедиться, что определенные структуры данных доступны только одному потоку за раз, вы должны использовать переносимую библиотеку потоков (например,pthread например), и оградить вашу функцию в качестве критического раздела.


Если под атомарным вы подразумеваете "только один поток за раз", то вы можете просто защитить функцию с помощью блока критического раздела (В Windows). В Linux я использую блокировку/разблокировку мьютекса для более или менее эмуляции критического раздела.


вы можете посмотреть в семафоры POSIX, мьютексы или тому подобное, которые могут работать как на Windows, так и на Linux.

используя, например, cygwin или minGW, можно даже написать переносимый код между Linux и Windows.

еще лучше вы можете создавать библиотеки windows на Linux:http://cdtdoug.blogspot.com/2009/05/mingw-cross-for-linux.html