子进程图标在Dock中弹回

时间:2013-05-11 16:40:53

标签: c++ macos debugging

我的应用程序启动一个子进程程序,通过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

注意:此代码可能是也可能不是我的问题的原因。作为第一步,我真的想证明原因是什么。

3 个答案:

答案 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_variablesfuturespromises

HTH

答案 2 :(得分:0)

我最终将子进程重写为MacOS XPC服务。在XPC服务的属性列表中,我添加了LSBackgroundOnly以使Launch Services忽略系统事件处理。