维护跨不同执行的 FIFO 可读
Maintaining a FIFO readable across different executions
我以前从未使用过命名管道,最近才意识到这正是我所需要的。
我正在 运行使用 gnu parallel 生成大量(GB 到 1TB,现在很难知道)针对 mySQL 上的数据库格式化的输出。
我发现我可以打开两个终端:
1 号航站楼得到类似:
find . -type f -name "*.h" | parallel --jobs 12 'cprogram {}' > /home/pipe
其中 pipe 是用 mkfifo
制作的 fifo。
在第二个终端上,我 运行 类似这样的命令:
mysql DataBaseName -e "LOAD DATA LOCAL INFILE '/home/pipe' INTO TABLE tableName";
有效...
但这很糟糕...如果我理解正确,当第一个进程结束导致管道关闭时会生成一个 EOF。
理想情况下,我希望 运行 具有不同参数的循环中的第一个进程。每次迭代都可能需要很长时间,我需要进行健全性检查,这样我就不会浪费一周的时间来发现我有错误或错误的逻辑。
我想知道如何以标准方式将 FIFO 用于此类过程。
If I understand correctly, there's an EOF generated when the first
process ends causing the pipe to close.
有点。还有一点比这更重要 - 从技术上讲管道在第一个进程结束后立即关闭是不正确的。
取而代之的是管道和 FIFO return EOF,当管道中没有更多的数据并且没有被任何进程打开进行写入时。
通常,这可以通过让 reader 进程打开 FIFO 进行读取和写入来解决,即使它永远不会写入 - 例如,通过从 FIFO 读取来接受本地客户端的服务器可以打开 FIFO 进行读写,这样当没有活动的客户端时,服务器就不必处理 EOF 的特殊情况。这是 "standard" 处理它的方法,如 UNIX 环境中的高级编程 关于 IPC 机制的章节中所述。
但在您的情况下,这实际上是不可能的,因为您没有保持 运行 的永久进程(也就是说,您没有服务器进程的等价物)。您基本上需要某种 "persistent writer",即在不同迭代期间保持管道打开以进行写入的过程。
我能想到的一个解决方案是在后台cat
标准输入到FIFO。这确保 cat
打开 FIFO 进行写入,因此始终有一个活动的写入器,但通过将其保留在后台,您实际上不会向它提供任何输入,它也永远不会写入 FIFO。请注意,一旦 cat
尝试从 stdin
读取(后台进程组中的进程 运行,作业将被 shell 停止(但不会终止)通常会发送 SIGTTIN 并在它们尝试从 stdin
读取时停止,因为它们在被带到前台之前没有控制终端)。不管怎样,只要你不给它任何输入,你就很好——进程处于停止状态,但 FIFO 仍然打开以进行写入。只要后台作业没有终止,您就永远不会在管道上看到 EOF。
所以,简而言之,你:
- 创建 FIFO:
mkfifo /home/pipe
- 启动打开 FIFO 进行写入的后台作业:
cat >/home/pipe &
- 运行 你想要的程序,你想要多少次迭代。忽略有关后台作业停止的 shell 消息。您可以这样保留它,因为即使作业已停止,管道仍处于打开状态以进行写入。
- 完成后,通过将其置于前台并发送 SIGINT(通常为 Ctrl+C)或使用
kill PID
. 来终止后台 cat
请注意,通过这样做,reader 进程(在本例中为 mysql)将永远不知道输入何时结束。它总是会阻止更多的输入,除非你在杀死 mysql.
之前杀死背景 cat
我以前从未使用过命名管道,最近才意识到这正是我所需要的。
我正在 运行使用 gnu parallel 生成大量(GB 到 1TB,现在很难知道)针对 mySQL 上的数据库格式化的输出。
我发现我可以打开两个终端: 1 号航站楼得到类似:
find . -type f -name "*.h" | parallel --jobs 12 'cprogram {}' > /home/pipe
其中 pipe 是用 mkfifo
制作的 fifo。
在第二个终端上,我 运行 类似这样的命令:
mysql DataBaseName -e "LOAD DATA LOCAL INFILE '/home/pipe' INTO TABLE tableName";
有效...
但这很糟糕...如果我理解正确,当第一个进程结束导致管道关闭时会生成一个 EOF。
理想情况下,我希望 运行 具有不同参数的循环中的第一个进程。每次迭代都可能需要很长时间,我需要进行健全性检查,这样我就不会浪费一周的时间来发现我有错误或错误的逻辑。
我想知道如何以标准方式将 FIFO 用于此类过程。
If I understand correctly, there's an EOF generated when the first process ends causing the pipe to close.
有点。还有一点比这更重要 - 从技术上讲管道在第一个进程结束后立即关闭是不正确的。
取而代之的是管道和 FIFO return EOF,当管道中没有更多的数据并且没有被任何进程打开进行写入时。
通常,这可以通过让 reader 进程打开 FIFO 进行读取和写入来解决,即使它永远不会写入 - 例如,通过从 FIFO 读取来接受本地客户端的服务器可以打开 FIFO 进行读写,这样当没有活动的客户端时,服务器就不必处理 EOF 的特殊情况。这是 "standard" 处理它的方法,如 UNIX 环境中的高级编程 关于 IPC 机制的章节中所述。
但在您的情况下,这实际上是不可能的,因为您没有保持 运行 的永久进程(也就是说,您没有服务器进程的等价物)。您基本上需要某种 "persistent writer",即在不同迭代期间保持管道打开以进行写入的过程。
我能想到的一个解决方案是在后台cat
标准输入到FIFO。这确保 cat
打开 FIFO 进行写入,因此始终有一个活动的写入器,但通过将其保留在后台,您实际上不会向它提供任何输入,它也永远不会写入 FIFO。请注意,一旦 cat
尝试从 stdin
读取(后台进程组中的进程 运行,作业将被 shell 停止(但不会终止)通常会发送 SIGTTIN 并在它们尝试从 stdin
读取时停止,因为它们在被带到前台之前没有控制终端)。不管怎样,只要你不给它任何输入,你就很好——进程处于停止状态,但 FIFO 仍然打开以进行写入。只要后台作业没有终止,您就永远不会在管道上看到 EOF。
所以,简而言之,你:
- 创建 FIFO:
mkfifo /home/pipe
- 启动打开 FIFO 进行写入的后台作业:
cat >/home/pipe &
- 运行 你想要的程序,你想要多少次迭代。忽略有关后台作业停止的 shell 消息。您可以这样保留它,因为即使作业已停止,管道仍处于打开状态以进行写入。
- 完成后,通过将其置于前台并发送 SIGINT(通常为 Ctrl+C)或使用
kill PID
. 来终止后台
cat
请注意,通过这样做,reader 进程(在本例中为 mysql)将永远不知道输入何时结束。它总是会阻止更多的输入,除非你在杀死 mysql.
之前杀死背景cat