Блокировка файлов и семафоры
просто из любопытства, каков предпочтительный способ достижения межпроцессной синхронизации в Linux? The sem*(2)
семейство системных вызовов, кажется, очень неуклюжий и устаревший интерфейс, в то время как есть три способа блокировки файлов - fcntl()
, flock()
и lockf()
.
каковы внутренние различия (если таковые имеются) и как бы вы оправдали использование каждого?
4 ответов
ни. Актуальные версии pthread_*
(напр. phtread_mutex_t
) все позволяют размещать переменные в общих сегментах, которые создаются через shm_open
. Вам просто нужно разместить дополнительный параметр для вызовов init.
не используйте семафоры (sem_t
) Если вы не должны, то они слишком низкоуровневы и interupted IO etc.
не злоупотребляйте файл замок для контроля процессов. Она не создана для этого. В частности, у вас нет возможности очистить метаданные файла например, блокировки, поэтому вы никогда не знаете, когда блокировка / разблокировка станет видимой для второго процесса.
вы страдаете богатством выбора из богатой истории, как отметил DarkDust. Для чего стоит мое дерево решений идет примерно так:
используйте мьютексы, когда только один процесс/поток может иметь доступ одновременно.
используйте семафоры, когда два или более (но все же конечных) процессов/потоков могут использовать ресурс.
используйте семафоры POSIX, если вам действительно не нужно что-то семафоры SYSV - например, отменить, PID последней операции, так далее.
используйте блокировку файлов на файлах или если выше не соответствует вашим требованиям каким-либо образом.
потенциально существенной разницей может быть справедливость распределения ресурсов. Я не знаю подробностей реализации semget/semop
семья, но я подозреваю, что он обычно реализуется как "традиционный" семафор, насколько идет планирование. Как правило, я считаю, что выпущенные потоки обрабатываются на основе FIFO (первый, ожидающий семафора, выпускается первым). Я не думаю, что это произойдет с блокировкой файла, так как я подозреваю (снова просто догадываюсь), что обработка не выполняется на уровне ядра.
у меня был существующий код, сидящий вокруг, чтобы проверить семафоры для целей IPC, и поэтому я сравнил две ситуации (один с использованием semop
и с помощью lockf
). Я сделал тест бедного человека и просто побежал к экземплярам приложения. Общий семафор использовался для синхронизации запуска. При запуске теста semop оба процесса завершили 3 миллиона циклов почти синхронно. С другой стороны, петля блокировки была далеко не такой справедливой. Один процесс обычно завершается, в то время как другой завершил только половину циклов.
цикл для теста semop выглядел следующим образом. The semwait
и semsignal
функции-это просто обертки для semop
звонки.
ct = myclock();
for ( i = 0; i < loops; i++ )
{
ret = semwait( "test", semid, 0 );
if ( ret < 0 ) { perror( "semwait" ); break; }
if (( i & 0x7f ) == 0x7f )
printf( "\r%d%%", (int)(i * 100.0 / loops ));
ret = semsignal( semid, 0 );
if ( ret < 0 ) { perror( "semsignal" ); break; }
}
printf( "\nsemop time: %d ms\n", myclock() - ct );
общее время выполнения для обоих методов было примерно одинаковым, хотя версия lockf на самом деле была быстрее в целом иногда из-за несправедливости планирования. Как только первый процесс будет завершен, другой процесс будет иметь бесспорный доступ для около 1,5 миллионов итераций и работать очень быстро.
при неоспоримом запуске (один процесс получения и освобождения блокировок), версия semop была быстрее. Это заняло около 2 секунд для 1 миллиона итераций, в то время как версия lockf заняла около 3 секунд.
это было запущено в следующей версии:
[]$ uname -r
2.6.11-1.1369_FC4smp
различные реализации блокировки / семафора все ожили на разных системах. В системе V Unix у вас было semget
/semop
, POSIX определил другую реализацию с помощью sem_init
, sem_wait
и sem_post
. И flock
возник в 4.2 BSD, насколько я мог узнать.
так как они все получили определенное значение Linux поддерживает их все теперь, чтобы сделать портирование легко. Кроме того,flock
является мьютексом (заблокированным или разблокированным), но sem*
функции (как SysV, так и POSIX) являются семафорами: они позволяют приложению предоставлять доступ нескольким параллельным процессам, например, вы можете разрешить доступ к ресурсу 4 процессам одновременно с семафорами. Вы можете реализовать мьютекс с семафорами, но не наоборот. Я помню, что в отличном "расширенное Программирование UNIX" Марк Дж. Рохкинд продемонстрировал, как передавать данные между процессами через семафоры (очень неэффективно, он сделал это только для того, чтобы доказать, что это можно сделать). Но я не мог найти ... что-нибудь надежное об эффективности.
Я думаю, это больше похоже на "Использовать то, что вы хотите".