文件locking与信号量

出于好奇,在Linux上实现进程间同步的首选方法是什么? 系统调用的sem*(2)系列似乎有一个非常笨拙和过时的接口,而有三种方法来locking文件 – fcntl()flock()lockf()

什么是内部的差异(如果有的话),你将如何certificate每个的用法?

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

不要使用信号量( sem_t ),如果你不需要的话,它们太低,被IO等干扰。

不要滥用文件锁定进行进程间控制。 这不是为了这个。 特别是,您无法清除文件元数据(如锁),因此您永远不会知道何时锁定/解锁将在第二个进程中可见。

正如DarkDust所指出的那样,你正在经历丰富的选择。 为什么值得我的决策树是这样的:

当一次只有一个进程/线程可以访问时,使用互斥锁。

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

使用POSIX信号量,除非你确实需要SYSV信号量 – 例如UNDO,最后操作的PID等。

对文件使用文件锁定,或者如果以上方式不符合您的要求。

潜在的重大差异可能是资源分配的公平性。 我不知道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版本更快。 花了大约2秒钟,100万次迭代,而lockf版本花了大约3秒钟。

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

 []$ uname -r 2.6.11-1.1369_FC4smp 

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

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

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