2009-08-07 38 views
0

我使用命名的System V信号量来锁定OSX和Linux上的所有应用程序中的文件。根据任何定义,不是最漂亮的API。正确销毁命名的系统V信号量

它似乎工作,但我不能完全弄清楚如何在每个人都完成后正确地销毁信号量。

通用逻辑是这样的:

创建:

[1]的线程或进程试图打开信号量与()由ftok为文件创建的key_t设置。 Set包含2个信号量。 [2]如果信号量集不存在,它将创建666个权限。 [3]“锁定”(其中一个信号)设置为释放状态(值1)。 [4]“引用计数”(同一组中的另一个信号量)递增。

锁定/解锁:

要锁定[5],线程减1,“锁定”信号量的值(具有撤销),从而等待如果它已经为零。要解锁[6],线程会将其加1,从而允许别人锁定它。

毁:

[7] “引用计数” 信号被试图递减(用IPC_NOWAIT标志)。 [8]它的值被检查为0,并且如果它是[9]信号集被销毁。

(也有基于线程本地存储逻辑层,使一个线程内锁递归)

的问题是:

  • 如何同步步骤[1] [2]? (如果信号集不存在,但是当我们计算星星时,它是由其他人创建的,所以现在创建也将失败)
  • 如何将步骤[4]与[8]同步以便[9]执行不是过早地杀了我?
  • 有没有其他的比赛条件?

PS:虽然POSIX信号有更漂亮的API,我不认为我能活下来sem_inlink()行为如下所述:

呼叫至sem_open()来重新创建或重新 - 连接到信号量是指在调用sem_unlink()后 之后的新信号量 。

所以我没有办法释放他们...

回答

1

几种方法:

首先,如果你的目标是锁定文件,然后使用文件锁定通话flock(2)fcntl(2)+F_SETLK,而不是一个信号量。恕我直言,这是最好的方法。

二,保持sem永远。你说得对,提案很活泼,你的措词表明新的sem客户端可能随时出现。你需要一个单独的同步机制,像一个单独的,长期生存的sem来控制你实际关心的sem的创建/销毁。你可以得到异域风情,并将其与专用的“等待零”驱动程序(mysembuf.sem_op := 0)结合起来,观看计数器sem并准备好IPC_RMID。呸。更好的办法是拥有一个单一的,持久的二进制信号量,而不需要用户提供的引用计数。

三,使用POSIX命名sems。忽略sem_unlink(),而不是简单的sem_close()完成后(当然后sem_post()解锁!)。这在概念上就像先前的方法 - 一个小的同步原始依然存在 - 但正如你所说,一个更简单的API。你也不必处理SysV semaphores' fatal flaw

+0

我不知道致命的缺陷:信号量的创造是原子的(我希望?)。下一个进程会实际得到它,或者最坏的情况是无法创建一个调用(应该简单地尝试在循环中再次获取它)。然后,直到创建过程释放它(设置为1),其他人将已经存在的sem,并且如果试图“锁定”(用-1),他们将等待。创建过程失去控制,但没关系,它们都是平等的。 – Eugene 2009-08-07 04:57:58

+0

(其实这就回答我的一个问题,我只是不想循环:)) – Eugene 2009-08-07 05:01:54

+0

至于保持一个sem,在linux上最大一般很小,比如128集。我只需要锁定几个文件,但是我的单元测试速度非常快 - 这是我不想使用的主要原因。 – Eugene 2009-08-07 05:07:57

0

这是我最终做的事情(这是一个荣誉,在这一点上,我不会离开直到我有正确的代码,无论它是否需要手头的任务:))。

创建

尝试打开[1]现有的SEM镶有3个SEMS,如果失败,尝试[2]创建一个。如果由于某人已经创建而无法创建,请返回[1]。这个循环最终会退出,无论是打开或创建的sem,还是因为我无法处理的错误,在这种情况下,我拿球并回家。 (我也有N次迭代的限制,以防万一:))。

3个sems中的一个是有效负载,另一个是引用计数,第三个是引用计数锁。 [2]锁定初始化为0后,锁定状态。

挡土墙

如果SEM组是由[2],所有3个SEMS被semoped [3]从0到1有效载荷被释放时,引用计数是1时,锁定被解除(没有撤消)中创建。 如果它被[1]打开,获取锁定[4](-1),ref计数递增(+1)并且锁定被释放(+1)。如果此时锁定为零,这将会阻止。如果这个semop由于sem set在我们等待的时候在[6]被销毁而失败,保留失败,我们一路回到[1]。这个循环的迭代次数也是有限的。

释放

获取锁[5](-1与等待),ref计数递减(-1没有等待)。如果成功,那么如果ref count现在为零,则sem集合将被销毁。否则[6]锁定被释放(+1)。如果由于sem集被破坏而导致锁失败 - 无所事事。

在保留和释放之间,有效载荷按照惯例使用。除了每集2个信号量的复杂性和开销之外,只有一个问题(现在我看到致命缺陷:)) - 当创建者在[2]和[3]之间崩溃时。这将挂死所有客户。我可以在Linux上使用定时等待并杀死孤立的信号量,但OSX,因为通常的白痴自我,没有定时操作,所以我有点拧...

* ...离开编写自己的内核或者其他的东西...*