gpt4 book ai didi

c - 无需轮询的 Linux 同步

转载 作者:太空宇宙 更新时间:2023-11-04 10:31:37 25 4
gpt4 key购买 nike

原则上我想要的很简单。

两个可执行文件 ./read./write 分别从一个资源(比方说一个文件)中读取和写入。使用 flock(2) 可以很容易地防止在任意时间任意调用 ./read./write 之间的竞争条件。

要求是 ./read 的每次调用都包含上一次调用的资源快照,如果当前资源与快照匹配,则 ./read应该等待( sleep )直到调用 ./write 更改资源。

据我所知,每个程序的程序流程应该是这样的:

//read.c
obtain mutex0
read resource
is resource same as our snapshot?
release mutex0 [1]
sleep until ./write says to wake up [2]
obtain mutex0
read resource
do something with resource
release mutex0

//write.c
obtain mutex0
change resource in some way
tell any sleeping ./read's to wake up
release mutex0

这种方法的主要问题是标记为 [1][2] 的行之间存在明显的延迟。这意味着 ./read 可以在 [1] 处释放 mutex0,整个调用 ./write可以完成,然后 [2] 执行,但会无限期停止,因为 ./write 已经尝试唤醒任何休眠的 ./read之前。

除了使用一个完整的独立的成熟服务器进程之外,没有简单的方法来做我想做的事吗?此外,对于那些好奇的人,我想为 CGI 中的应用程序执行此操作。

最佳答案

不,阅读器的程序流程不正确。您需要某种锁定机制来防止在进行一个或多个读取时写入,还需要某种唤醒机制来在写入完成时通知读者。

作者的程序流程没问题:

    # Initial read of file contents
Obtain lock
Read file
Release lock

# Whenever wishes to modify file:
Obtain lock
Modify file
Signal readers
Release lock

读者的程序流程应该是:

    # Initial read of file contents
Obtain lock
Read file
Release lock

# Wait and respond to changes in file
On signal:
Obtain lock
Read file
Release lock
Do something with modified file contents

如果只有一个读者,那么共享内存中的互斥锁 ( pthread_mutex_t ) 就足够了(所有作者和读者都可以访问);否则,我建议改用 rwlock ( pthread_rwlock_t)。为了唤醒任何等待的读者,广播一个条件变量(pthread_cond_t)。当然,困难在于设置共享内存。


咨询文件锁定和 fanotify接口(interface)也足够了。读者安装一个 fanotify FAN_MODIFY 标记,只需等待相应的事件即可。写入者不需要合作,除了使用建议锁(它的存在只是为了在文件被修改时阻止读者读取)。

不幸的是,该接口(interface)当前需要 CAP_SYS_ADMIN 功能,您绝对不希望随机 CGI 程序具有该功能。


咨询文件锁定和 inotify接口(interface)就足够了,我相信最适合这个,当读者和作者都为每组操作打开和关闭文件时。对于读者来说,本案例的程序流程是:

Initialize inotify interface
Add inotify watch for IN_CREATE and IN_CLOSE_WRITE for "file"

Open "file" read-only
Obtain shared/read-lock
Read contents
Release lock
Close "file"

Loop:
Read events from inotify descriptor.
If IN_CREATE or IN_CLOSE_WRITE for "file":
Open "file" read-only
Obtain shared/read-lock
Read contents
Release lock
Close "file"
Do something with file contents

作者还只是

    # Initial read of file contents
Open "file" for read-only
Obtain shared/read-lock on "file"
Read contents
Release lock
Close "file"

# Whenever wishes to modify file:
Open "file" for read-write
Obtain exclusive/write-lock
Modify file
Release lock
Close "file"

即使写者没有获得锁,写者关闭文件时也会通知读者;唯一的风险是当读者正在读取文件时,另一组更改被写入(由另一个锁拒绝修饰符)。

即使修改器用新文件替换文件,当新文件准备就绪时(重命名/链接到旧文件之上,或者新文件创建者关闭文件),读者也会得到正确通知。重要的是要注意,如果读者保持文件打开,他们的文件描述符不会神奇地跳转到新文件,他们只会看到旧的(可能已删除的)内容。


如果出于某种重要原因,读者和作者不关闭文件,读者仍然可以使用 inotify,但使用 IN_MODIFY 标记,以便在文件被截断或写入时得到通知到。在这种情况下,重要的是要记住,如果文件随后被替换(重命名,或删除并重新创建),读者和作者将看不到新文件,但将对旧的、现在不可见的文件进行操作-文件系统文件内容。

读者程序流程:

Initialize inotify interface
Add inotify watch for IN_MODIFY for "file"

Open "file" read-only
Obtain shared/read-lock
Read contents
Release lock

Loop:
Read events from inotify descriptor.
If IN_CREATE or IN_CLOSE_WRITE for "file":
Obtain shared/read-lock on "file"
Read contents
Release lock
Do something with file contents

编写器的程序流程仍然几乎相同:

    # Initial read of file contents
Open "file" for read-only
Obtain shared/read-lock on "file"
Read contents
Release lock
Close "file"

Open "file" for read-write

# Whenever writer wishes to modify the file:
Obtain exclusive/write-lock
Modify file
Release lock

重要的是要注意 inotify 事件是在事后发生的。通常会有一些小的延迟,这可能取决于机器上的负载。因此,如果对文件更改的快速响应对于系统正常工作很重要,则您可能必须改用互斥锁或 rwlock 以及共享内存方法中的条件变量。

根据我的经验,这些延迟往往比典型的人类 react 间隔要短。因此,我认为——我也建议你这样做——inotify 接口(interface)在人类时间尺度上足够快速和可靠;在毫秒和亚毫秒机器时间尺度上并非如此。

关于c - 无需轮询的 Linux 同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39600593/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com