shm_open和ftruncate竞争条件可能吗?

时间:2013-05-11 23:40:08

标签: c++ c linux shared-memory mmap

来自shm_open手册页:

  

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

这不会使应用程序暴露于竞争状态吗?请考虑以下伪代码:

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调用(一起)不是原子的,因此您可能会遇到一个竞争条件,即一个进程调用shm_openCREATE case)但之前调用ftruncate,另一个进程调用shm_openGET_EXISTING case)并尝试mmap 0大小的对象,甚至可能写入它。

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

  1. 使用IPC互斥锁/信号量使整个事物同步,或者......

  2. 如果它是安全的(按POSIX),请在ftruncateCREATE案件中致电GET_EXISTING

  3. 避免这种竞争条件的首选方法是什么?

2 个答案:

答案 0 :(得分:5)

您的方法(从两者调用ftruncate)应该可行,但您需要一种方法来同步使用共享内存段的内容。由于内存最初是空的(零填充),因此不包含有效的同步对象,除非您要使用atomics自行滚动,否则无论如何都需要辅助形式的同步来控制对共享内存的访问。 / p>

我认为通常情况下,您不希望多个流程竞争创建或打开具有固定名称的共享内存段,而是希望拥有一个负责创建带有 random <的段的所有者进程/ em> name,使用O_EXCL来避免随机或恶意冲突,然后在您成功打开名称,将其大小并在其中创建同步对象后,将名称传递给需要访问的其他进程它

答案 1 :(得分:0)

作为@R。这里提到的另一个问题是,创建文件后,在内容(例如互斥锁)初始化并准备好使用之前,仍然有一个窗口。

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

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

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

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