shm_open和ftruncate竞争条件可能吗?

shm_open手册页:

新的共享内存对象最初长度为零。 对象的大小可以使用ftruncate(2)来设置。 […] shm_open()函数本身不会创build指定大小的共享对象,因为这样做会复制一个现有函数,该函数设置由文件描述符引用的对象的大小。

这是不是将应用程序暴露给竞争条件? 考虑下面的伪代码:

 int fd = shm_open("/foo", CREATE); if ( fd is valid ) { // created shm object, so set its size ftruncate(fd, 128); } else { fd = shm_open("/foo", GET_EXISTING); } void* mem = mmap(fd, 128); 

由于shm_openftruncate调用不是primefaces的,所以你可能会有一个竞争条件,一个进程调用shm_openCREATE case),但是在调用ftruncate之前,另一个进程调用shm_openGET_EXISTING case)并尝试mmap 0大小,甚至可能写入。

我可以想到两种方法来避免这种竞争条件:

  1. 使用IPC互斥/信号量使整个事情同步,或…

  2. 如果安全(每个POSIX),请在CREATEGET_EXISTING情况下调用ftruncate

哪个是避免这种竞争条件的首选方法?

你的方法(从这两个调用ftruncate )应该可以工作,但是你需要一种方法来同步共享内存段的内容 。 由于内存最初是空的(零填充),因此不包含有效的同步对象,除非您要使用原子来自己制作自己的内存,否则无论如何都需要一个辅助的同步形式来控制对共享内存的访问。

我会正常地思考,而不是有多个进程竞争来创建或打开一个固定名称的共享内存段,你会想要一个拥有者进程负责创建一个随机的名称段,使用O_EXCL以避免随机或恶意的冲突,然后在成功打开它的同时传递该名称,调整它的大小并在其中创建同步对象,然后传递给其他需要访问它的进程。

作为@R。 暗示,另一个问题是,在创建文件之前,还有一个窗口在内容之前(例如互斥体)被初始化并准备好使用。

与上述略有不同的解决方案是:

尝试打开()。 如果open()成功,只需映射()并使用必要的保证(见下文),内容已经被初始化并且很好走。 如果open()失败,则创建并初始化临时文件,然后尝试将临时文件作为所需文件进行硬链接,并取消链接()临时名称。

如果链接()成功,我们现在已经为我们自己和其他进程提供了初始化文件。 如果link()与EEXIST失败,则另一个进程首先到达那里(与rename()不同,如果目标名称存在,则link()失败)。 无论哪种方式,我们重复打开()应该现在成功与初始化准备使用文件。

通过这种策略,临时文件的初始化显然存在竞争条件,但是假设初始化过程是幂等性的,而不是过度昂贵的资源,并且每个进程选择一个唯一的临时文件,这是不重要的。 如果多个初始化可能是一个问题,一个解决方案是将初始化分成两个阶段的过程,第一阶段只是在文件中的一个互斥体,用于防止在第二阶段期间多次初始化文件的其余部分。