我有一个程序可以启动自身的其他实例。每个实例都会将标准输出流重定向到不同的文件。我遇到了以下事件链问题:
- 执行包含命令的 BAT 文件
my_program.exe > output_launcher.txt
- my_program.exe 使用命令启动更多自身实例
my_program.exe > output_1.txt
,并且my_program.exe > output_2.txt
- 原始实例(
my_program.exe > output_launcher.txt
)退出,而启动的两个实例(my_program.exe > output_1.txt
和my_program.exe > output_2.txt
)继续执行。 - 与 #1 相同的 BAT 文件再次被执行。
- 的新实例
my_program.exe > output_launcher.txt
失败,并出现错误“该进程无法访问该文件,因为它正在被另一个进程使用。”
如果来自#1的BAT文件没有重定向输出,则我不会收到错误,并且如果两个启动的实例在第二次执行BAT文件之前退出,则我不会收到错误。
因此,我假设 CMD.EXE 拥有 output_launcher.txt 文件的专有权利,直到所有子进程完成。
首先,这是一个好的假设吗?
我希望发生的是,当原始实例存在于#3中时,CMD.EXE放弃对output_launcher.txt的权利,因为每个子进程都重定向到它自己的文件。
重定向标准输出时是否可行?我能想到的最佳替代方案是实际将日志文件位置作为命令行参数,然后直接从我的程序写入文件,而不是重定向标准输出。不过,这会给我带来更多工作,因此如果可能的话,我想避免这种方式。
谢谢!
编辑:第一个实例用于启动其他实例的实际命令行如下所示start cmd /C "call my_program.exe > output_1.txt"
。然后我将该命令传递给“system()”函数(my_program.exe 是用 MSDN C 编写的)。
也许我可以采用不同的方式启动额外的实例以提供帮助?
答案1
经过一些简单的测试,我认为你的假设似乎是正确的。如果你想验证这一点,我建议进程黑客。(顶部有一个“下载”按钮;请小心,因为广告会显示不良的下载链接。)转到 Hacker,查找句柄或 DLL...(Ctrl-F)
使用它您可以轻松验证正在使用该文件的内容,并且通过重新执行查找,可以验证文件的发布时间。
我希望 Process Explorer 也能做类似的事情。
请注意,最好写入一个唯一的文件名...考虑一下:不要将第一个子调用 output_1.txt 和第二个子调用 output_2.txt 分开,而是检查哪些文件已经存在。然后继续往上,这样您就不会因为文件正在使用而无法追加而最终覆盖文件或遇到问题。操作系统和编程语言经常提供生成唯一文件名的功能。
您可能希望写入许多临时文件,然后将它们合并为更少的文件。这个想法是否有意义,或者根本没有意义,可能取决于您的项目以及您的处理方式。
如果您有 program.exe 的源代码,则无需运行“program.exe > filename”,只需使用“program.exe filename”。将代码放入程序中以快速写入文件,然后关闭文件,以便在没有活动写入时不再阻止它。(更彻底的过程甚至可能执行一些“锁定”……由于您正在运行该程序的多个副本,因此实际上可能值得投资。)不要调用 printf(),而是使用自定义函数,该函数仅在未指定输出文件时调用 printf(),否则它将写入文件。然后,您无需在每次更改输出文件时更改所有 printf() 调用,而只需更改传递给自定义输出函数的一个变量的值。我知道您说这可能不是更好的选择,因为需要花费更多时间。但是,我要告诉您,在我想出这种方法后,我个人节省了很多时间和精力。我认为这是一个很好的长期解决方案。
或者,考虑使用操作系统的日志记录功能。这可以通过从命令行运行命令来完成:在 Unix 中,运行“logger”;在 MS Windows 中,运行事件创建。应该有方法可以直接从您选择的编程语言(如您所指出的 MSDN C)中执行此操作。如果您的输出很长,或者您担心会使您的操作系统日志混乱,那么这可能并不理想。(我知道有些地方会主动监控操作系统日志。)
答案2
这是一个合理的假设。
1) 请确认该文件未在任何其他应用程序中打开。一个合理的方法是尝试在 .bat 应用程序未运行时重命名文件。如果此方法失败,则表明其他应用程序正在打开该文件。
2)您可以尝试使用追加运算符>>,然后>告诉我会发生什么吗?