我的应用程序启动一个子进程程序,通过fork()
和管道使用QuickTime框架读取视频。子进程在不忙时进入等待循环,即直到有输入才进行usleep
。子进程不是GUI应用程序,而是用C ++编写的。
打开使用MSVC编解码器编码的AVI视频时,应用程序图标的第二个副本显示在停靠栏中并跳出。在Activity Monitor中大约30秒后,我可以看到子进程变为“无响应”,即使CPU看起来是~0%。子进程仍在运行并响应;只是活动监视器说不然。
如果我通过gdb attach
查看子进程的状态或检查其输出;一切都很好。我可以告诉子进程关闭文件并打开另一个文件并继续使用它,此时弹跳停靠图标消失,进程未标记为无响应。
就好像OSX认为我的子进程已崩溃(?)但我无法检测到异常。
如何停止在Dock中显示图标的子流程,弹跳并标记为无响应?
这就是我如何设置与子进程的通信:
#include <unistd.h>
#define READ 0
#define WRITE 1
// Start process
pid_t popen2(const char *command, char * const argv[], int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
// Set up pipes
if(pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return(-1);
pid = fork();
if(pid < 0)
return(pid);
else if(pid == 0)
{
// Set up communication via stdin/out
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execvp(command, argv); // run subprocess
perror("execvp");
exit(1);
}
// Provide pointers to the file descriptors to the caller
if(infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if(outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return(pid);
}
有关popen2()
的更多讨论,请参阅this SO question。
注意:此代码可能是也可能不是我的问题的原因。作为第一步,我真的想证明原因是什么。
答案 0 :(得分:2)
“无响应”部分很简单:您的子进程没有运行任何类型的runloop,因此从系统的POV开始,它不处理事件。
我为什么你的新进程获得一个停靠图标有点模糊,但它基本上归结为fork()
创建一个继承父进程属性的进程(在这种情况下,它是前台应用程序)。 OS X有许多机制以比fork()
更合理的方式启动子进程。如果您的应用位于Cocoa中,请使用NSTask
,否则请查看posix_spawn(2)
。
这应该是您日常工作的替代品:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <spawn.h>
#include <signal.h>
#include <crt_externs.h>
#define READ 0
#define WRITE 1
#define environ (*_NSGetEnviron())
pid_t popen2(const char *command, char * const argv[], int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if(pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return(-1);
posix_spawn_file_actions_t file_actions;
posix_spawn_file_actions_init(&file_actions);
posix_spawn_file_actions_adddup2(&file_actions, p_stdin[READ], 0);
posix_spawn_file_actions_adddup2(&file_actions, p_stdout[WRITE], 1);
posix_spawn_file_actions_adddup2(&file_actions, 2, 2);
posix_spawnattr_t spawnAttributes;
posix_spawnattr_init(&spawnAttributes);
sigset_t no_signals;
sigset_t all_signals;
sigemptyset (&no_signals);
sigfillset (&all_signals);
posix_spawnattr_setsigmask(&spawnAttributes, &no_signals);
posix_spawnattr_setsigdefault(&spawnAttributes, &all_signals);
short flags = POSIX_SPAWN_CLOEXEC_DEFAULT | POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF;
posix_spawnattr_setflags(&spawnAttributes, flags);
if (posix_spawn(&pid, command, &file_actions, &spawnAttributes, argv, environ)) {
perror("posix_spawn");
exit(1);
}
close(p_stdin[READ]);
if(infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
close(p_stdout[WRITE]);
if(outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return(pid);
}
答案 1 :(得分:0)
如果您使用的是支持c ++ 11的编译器,我建议您查看packaged_tasks。
或者,您也可以使用condition_variables,但我会先尝试使用打包的任务。条件变量比较高级别的打包任务更具原始性。无论哪种方式,使用这些机制比传统IPC技术更容易(并且符合标准)。
当然,如果您不需要单独的流程。
有关详细信息,我强烈建议您查看The C++ Programming Language, 4th Edition。它有一个简单的生产者/消费者机制的例子,它有一个简单的矢量,可能很适合你。如果你没有参考这本书,我相信你可以在网上找到类似的例子来使用condition_variables,futures或promises。
HTH
答案 2 :(得分:0)
我最终将子进程重写为MacOS XPC服务。在XPC服务的属性列表中,我添加了LSBackgroundOnly以使Launch Services忽略系统事件处理。