Атомарные функции unix

Атомарные функции unix

11.05.2012 04:15:20 Просмотров 20 Источник

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

У вопроса есть решение - Посмотреть?

https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix#comment109376_109368
IMHO нет. Используйте sigprocmask() и мьютексы или семафоры.
https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix#comment109382_109368
@avp, sigprocmask() разве может помешать передать управление другому потоку?
https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix#comment109391_109368
@northerner, вопрос о пользовательском пространстве, но как таковой защиты данных в данном случае не требуется,- хочется чтобы при получении сигнала завершения обработчик не прерывался и не передавал управление другим потокам, и не хочется растягивать обработчик и посылать им pthread_cancel(). Может еще способы есть красиво выйти при завершении, чтобы остальные потоки не пытались читать уже несуществующие данные?
https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix#comment109405_109368
@margosh, sigprocmask() помогает только блокировать прерывание. Если в "заблокированной" секции истечет квант времени планировщика или будет сделан системный вызов, то конечно, поток может быть переключен. А в многопроцессорной системе у Вас все равно одновременно (физически одновременно) будут исполняться несколько потоков. Так что общие данные (для многопоточной программы) надо в любом случае защищать мьютексами (семафорами). sigprocmask() просто помогает исключить возможное влияние обработчика сигнала на участок кода потока. -- А что Вы называете "обработчик" в своем комментарии ?
https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix#comment109407_109368
@avp, Функцию, которую регистрирую в sigaction()
https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix#comment109413_109368
@margosh, извините, но если Вы допускаете "и посылать им pthread_cancel()", то это какое-то недопонимание ситуации. Обработчик сигнала (именно его регистрируют в sigaction()) не следует связывать с определенным потоком. Конечно, при определенных усилиях, можно добиться, чтобы некий сигнал обрабатывался только в конкретном потоке, но зачем ???. Более того, ни одну из функций связанных с posix threads из этого обработчика вызывать нельзя. IMHO из механизмов синхронизации в нем доступен только sem_post() (ну, не считая kill(), write()...). См. man 7 signal. Там есть список функций
https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix#comment109614_109368
В википедии в статье Critial section есть пример для pthread (с мьютексами) en.wikipedia.org/wiki/Critical_section
https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix#comment109624_109368
@avp, Вы правы, pthread_cancel() использовать нельзя. Я зря на планировщике зациклилась, атомарность функции на многопроцессорной системе меня не спасет. В таком случае, не подскажите, как обычно реализуется обработчик SIGTERM в многопоточной программе? Получается, что большую часть ресурсов я освободить в нем не могу...

Ответы - Атомарные функции unix / Атомарные функции unix

Является ответом!
avp

12.05.2012 01:35:16

@margosh, лично я обычно во всех обработчиках всех сигналов просто выставляю флаг (в volatile int переменной). (В тестовом режиме не боюсь вызывать printf()).

Если обработчик сигнала и функции, которые этот сигнал интересует, хорошо локализуются по смыслу задачи, то я пишу их в одном файле и флаг объявляю static, иначе делаю флаг extern.

Безусловно, проверка флага с целью выполнения каких-то действий и затем его сброса должна быть защищена мьютексом (от потоков) и sigprocmask() (от сигнала).

Видимо у Вас, при такой схеме, один из потоков (планировщик) должен иметь маску сигналов, разрешающую SIGTERM, а все остальные маску с заблокированным SIGTERM. В таком случае прерывание ожидания (read(), select(), sigpause(), sleep() и т.п.) после обработки сигнала произойдет именно в нужном, а не в произвольном потоке. Иначе планировщик может никогда изменения флага не увидеть.

Другое решение состоит в записи (системным вызовом write()) обработчиком сигнала в pipe некоторой "команды". В дальнейшем какой-то поток (в Вашем случае планировщик) может прочесть ее и выполнить необходимые действия.

IMHO что-то в таком духе (по крайней мере в Linux).

Вообще же, очень часто, достаточно SIGTERM просто не ловить т.к. на самом деле никакие реально нужные ресурсы не пропадают. Вы просто для себя рассмотрите случай с SIGKILL в произвольный момент - катастрофа произойдет ?

Отловить завершение и зафиксировать в логах можно враппером.

https://ru.stackoverflow.com/questions/109368/%d0%90%d1%82%d0%be%d0%bc%d0%b0%d1%80%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-unix/109669#comment109674_109669
@avp, Спасибо за подробный ответ, подумаю, что лучше подойдет!
Закрыть X