Блокировка файлов и семафоры

просто из любопытства, каков предпочтительный способ достижения межпроцессной синхронизации в 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" Марк Дж. Рохкинд продемонстрировал, как передавать данные между процессами через семафоры (очень неэффективно, он сделал это только для того, чтобы доказать, что это можно сделать). Но я не мог найти ... что-нибудь надежное об эффективности.

Я думаю, это больше похоже на "Использовать то, что вы хотите".