Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 正确销毁命名的SystemV信号量_Multithreading_Ipc_Semaphore_File Locking - Fatal编程技术网

Multithreading 正确销毁命名的SystemV信号量

Multithreading 正确销毁命名的SystemV信号量,multithreading,ipc,semaphore,file-locking,Multithreading,Ipc,Semaphore,File Locking,我使用命名SystemV信号量在OSX和linux上的所有应用程序中锁定一个文件。从任何定义来看,都不是最漂亮的API 它似乎可以工作,但我不太明白在每个人都使用完信号灯后如何正确地销毁它 一般逻辑如下: 创建: [1] 线程或进程尝试使用ftok()为文件创建的密钥打开信号量集。集合包含2个信号量。[2] 如果信号量集不存在,则使用666权限创建它。[3] “锁定”(信号量之一)设置为释放状态(值1)。[4] “引用计数”(同一集中的另一个信号量)增加 锁定/解锁: 为了锁定[5],一个线程将

我使用命名SystemV信号量在OSX和linux上的所有应用程序中锁定一个文件。从任何定义来看,都不是最漂亮的API

它似乎可以工作,但我不太明白在每个人都使用完信号灯后如何正确地销毁它

一般逻辑如下:

创建:

[1] 线程或进程尝试使用ftok()为文件创建的密钥打开信号量集。集合包含2个信号量。[2] 如果信号量集不存在,则使用666权限创建它。[3] “锁定”(信号量之一)设置为释放状态(值1)。[4] “引用计数”(同一集中的另一个信号量)增加

锁定/解锁:

为了锁定[5],一个线程将“lock”信号量的值递减1(使用undo),从而等待它是否已经为零。要解锁[6],线程将其增量为1,从而允许其他人锁定它

销毁:

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

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

问题是:

  • 如何同步步骤[1]和[2]?(若信号量集不存在,但当我们数星星时,它是由其他人创建的,所以现在创建也将失败)
  • 如何使步骤[4]与[8]同步,以便[9]不会过早地杀死我
  • 还有其他比赛条件吗
PS:虽然POSIX信号量有更好的API,但我认为我无法在这里描述的sem_inlink()行为中生存下来:

调用sem_open()以重新创建或 重新连接到信号灯,请参阅 sem_unlink()之后的新信号量为 打电话来

所以我没有办法释放它们…

几种方法:

首先,如果您的目标是锁定一个文件,那么使用文件锁定调用
flock(2)
fcntl(2)+F_SETLK
,而不是信号灯。嗯,这是最好的办法

其次,永远保持一个sem。你说得对,这个提议很有意思,而且你的措辞表明新的sem客户随时可能出现。您需要一个单独的同步机制,比如一个单独的、长寿命的sem,来控制您真正关心的sem的创建/销毁。你可以把它和一个专用的“等待零”(mysembuf.sem\u op:=0)破坏者结合起来,观察refcount sem并准备好
IPC\u RMID
。讨厌。最好只使用一个持久的二进制信号量,而不使用用户提供的引用计数


第三,使用POSIX命名的SEM。忽略
sem\u unlink()
,而在完成后只需
sem\u close()
(当然是在
sem\u post()
ing解锁之后!)。这在概念上与前面的方法类似——一个小的同步原语仍然存在——但是,正如您所说,它是一个更简单的API。您也不必处理。

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

创建

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

三个SEM中的一个是有效负载,另一个是参考计数,第三个是参考计数锁。[2]锁初始化为0后,将进入锁定状态

保留

如果sem集是由[2]创建的,则所有3个sem都将从0到1进行符号化[3]。有效负载释放,参考计数为1,锁释放(无撤消)。 如果它是由[1]打开的,则获取锁[4](-1),引用计数增加(+1),锁释放(+1)。如果此时lock为零,则会被阻塞。如果在等待过程中,由于sem集在[6]被破坏,导致此semop失败,则保留失败,我们将返回到[1]。这个循环的迭代次数也有限

发布

获取锁[5](-1,等待),减少引用计数(-1,不等待)。如果成功,那么如果ref count现在为零,则sem集将被销毁。否则[6]锁被释放(+1)。如果因为sem集被破坏而获取锁失败,则什么也不做

在保持和释放之间,有效载荷照常使用

除了每个集合2个信号量的复杂性和开销之外,只有一个问题(现在我看到了致命的缺陷:)——当creator在[2]和[3]之间崩溃时。这将绞死所有客户。我可以在linux上使用定时等待并杀死孤立的信号量,但是OSX,作为一个通常愚蠢的自己,没有定时操作,所以我有点搞砸了


*…去编写自己的内核或其他东西…*

我不确定致命的缺陷:信号量的创建是原子的(我希望是?)。下一个进程将实际获取它,或者在最坏的情况下,调用create失败(这应该只是尝试在循环中再次获取它)。然后,直到创建流程释放它(设置为1),其他所有人都将获得已经存在的sem,如果试图“锁定”(使用-1),他们将等待。创建过程失去了控制,但没关系,它们都是相等的。(实际上,这回答了我的一个问题,我只是不想循环:))至于永远保持一个sem,在linux上,最大值通常很小,大约128集。我只需要锁定几个文件,但我的单元测试达到它相当快——这是我想在不使用时杀死它们的主要原因。至于文件锁定,我四处看了看,似乎一个进程的线程无法锁定每个进程