Обработчик сигнала, обращающийся к структуре данных очереди (состояние гонки?)
В настоящее время я пишу небольшую оболочку на C++.
Задания и связанные с ними PID хранятся в очереди указателей заданий. (job *)
, Когда запускается новое задание, информация о нем добавляется в очередь. Так как несколько заданий могут обрабатываться одновременно и новые задания могут быть введены в консоли оболочки в любое время, у меня есть обработчик сигнала, который ожидает выполнения заданий, которые прекращаются.
Когда работа прекращается, мне нужно удалить ее информацию из активной очереди и переместить ее в мою очередь завершенных работ. Однако, возможно, что новое задание пользователя добавляется в очередь, когда другое задание останавливается.
В таком случае их insert
операция очереди была бы приостановлена, и мой обработчик сигнала был бы вызван, который выполнил бы это pop
операция.
Я пытаюсь понять, как я могу решить это потенциальное состояние гонки, поскольку я предполагаю, что коррупция может произойти во время этого процесса. Я не могу использовать мьютекс, поскольку возникнет взаимоблокировка, если прерванный родительский процесс использует очередь в то время.
Я вижу некоторую информацию о C++11
быть способным к атомарным операциям, как заявлено пользователем, наряду с информацией о тасклетах. Я не уверен, имеют ли они отношение к моему вопросу все же.
Интересно, что пример оболочки (MSH - http://code.google.com/p/mini-shell-msh/), которую я использую в качестве справки, по-видимому, не обрабатывает такие условия. Обработчик сигнала сразу же изменяет список заданий вместе с главной консолью. Возможно, здесь есть что-то, что я пропускаю?
Как всегда, все отзывы оценены.
2 ответа
У вас есть несколько способов избежать состояния гонки.
- Использовать свободную (атомарную) очередь для указателей заданий;
- использовать любой другой вид очереди, но защитить его
sigprocmask
(в коде не обработчика) и с надлежащимsa_mask
значение вsigaction
вызов; - вообще не используйте обработчик сигналов, используйте непереносимый системный вызов, который позволяет работать с сигналами синхронно: в Linux это возможно с
signalfd
, не уверен насчет других платформ.
Вам нужно отключить сигналы с sigprocmask()
вокруг ваших критических разделов в коде не обработчика. Это аналогично драйверам устройств в ядре, отключающим прерывания в пользовательской половине драйвера при обновлении структур, используемых совместно с обработчиком прерываний.