文件锁定与信号量

时间:2010-08-25 17:52:41

标签: c linux unix interprocess

出于好奇,在Linux上实现进程间同步的首选方法是什么? sem*(2)系列调用似乎有一个非常笨重和过时的界面,而有三种方法可以锁定文件 - fcntl()flock()lockf()

内部差异是什么(如果有的话)以及如何证明每种差异的使用?

4 个答案:

答案 0 :(得分:8)

都不是。 pthread_*的实际版本(例如phtread_mutex_t)都允许将变量放在通过shm_open创建的共享段中。您只需要在init调用中添加一些额外的参数。

如果不需要,请不要使用信号量(sem_t),它们的级别太低而且会被IO等中断。

不要滥用文件锁定进行进程间控制。它不是为此而做的。特别是,您无法刷新文件元数据(如锁定),因此您永远不会知道第二个进程何时可以看到锁定/解锁。

答案 1 :(得分:4)

正如DarkDust所说,你正在从丰富的历史中获得丰富的选择。对于它的价值我的决策树是这样的:

当一个进程/线程一次只能访问时使用互斥锁。

当两个或更多(但仍然是有限的)进程/线程可以使用资源时使用信号量。

使用POSIX信号量,除非你真的需要一些SYSV信号量 - 例如UNDO,最后一次操作的PID等

对文件使用文件锁定,或者如果上述内容不符合您的要求。

答案 2 :(得分:3)

不同的锁定/信号量实现都在不同的系统上实现。在System V Unix上,您有semget / semop,POSIX使用sem_initsem_waitsem_post定义了不同的实现。 flock起源于4.2BSD,据我所知。

由于它们都获得了一定的意义,因此Linux现在支持它们以便轻松移植。此外,flock是互斥锁(锁定或解锁),但sem*函数(SysV和POSIX)都是信号量:它们允许应用程序授予多个并发进程访问权限,例如:您可以允许与信号量同时访问资源到4个进程。您可以使用信号量实现互斥锁,但不能反过来实现。我记得在Marc J. Rochkind的优秀“高级UNIX编程”中,他演示了如何通过信号量在进程之间传输数据(非常低效,他只是为了证明它可以完成)。但我找不到任何关于效率的可靠信息。

我想这更像是“使用你想要的东西”。

答案 3 :(得分:2)

潜在的重大差异可能是资源分配的公平性。我不知道semget/semop系列的实现细节,但我怀疑它通常是作为“传统”信号量实现的。通常,我相信释放的线程是在FIFO的基础上处理的(首先释放等待信号量的第一个)。我不认为这会发生在文件锁定中,因为我怀疑(再次猜测)处理不是在内核级别执行的。

我有现成的代码来测试信号量以用于IPC目的,因此我比较了两种情况(一种使用semop,另一种使用lockf)。我做了一个穷人的测试,然后跑到应用程序的实例。共享信号量用于同步开始。在运行semop测试时,两个进程几乎同步完成了300万个循环。另一方面,lockf循环并不那么公平。一个过程通常会完成,而另一个过程只完成一半循环。

semop测试的循环如下所示。 semwaitsemsignal函数只是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版本总体上更快。一旦第一个过程完成,另一个过程将有大约150万次迭代的无争议访问,并且运行速度非常快。

当无争议地运行时(单个进程获取并释放锁),semop版本更快。 100万次迭代花费了大约2秒钟,而lockf版本花费了大约3秒钟。

这是在以下版本上运行的:

[]$ uname -r
2.6.11-1.1369_FC4smp
相关问题