【问题标题】:main process -> pthread -> fork + execvp主进程 -> pthread -> fork + execvp
【发布时间】:2014-12-12 14:35:48
【问题描述】:

我看到一个奇怪的问题。

有时当我运行我的程序足够长的时间时,我会看到我的程序有两个副本正在运行。第二个是第一个的子进程,因为我看到第二个的父 PID 是第一个的父 PID。

我意识到我的代码中有一个 fork,正因为如此,我才能运行两个副本——否则我永远无法运行我的程序的两个副本。

这种情况很少发生,但确实会发生。

架构如下:

主程序得到一个事件并产生一个 pthread。在那个线程中,我进行了一些处理,并根据一些结果,我立即执行了一个 fork,然后是一个 execvp。

我意识到从 pthread 调用 fork 并不是最好的方法,但在我的设计中,主进程会收到许多事件,而并行处理所有这些事件的唯一方法是使用 pthread。每个 pthread 都进行一些处理,在某些情况下,它需要调用不同的程序(为此我使用 execvp)。因为我不得不调用一个不同的程序,所以我不得不使用 fork

我想知道是否因为我最终会从线程上下文中调用 fork,是否有可能多个线程并行调用 fork + execvp,而这种“不知何故”会导致创建两个副本。

如果这确实发生了,如果我用互斥锁保护执行 fork+execvp 的代码会有所帮助,因为这将导致只有一个线程调用 fork + execvp。

但是,如果我在 fork + excvp 之前使用互斥锁,那么我不知道何时释放它。

如有任何帮助,我们将不胜感激。

执行 fork + execvp 的线程代码——以防你们在那里发现问题:

在 main.c 中

    status = pthread_create(&worker_thread, tattr, 
                                 do_some_useful_work, some_pointer);

[剪辑]

    void *do_some_useful_work (void * arg)
    {
          /* Do some processing and fill pArguments array */

          child_pid = fork();

          if (child_pid == 0)
          {
              char *temp_log_file;

              temp_log_file = (void *) malloc (strlen(FORK_LOG_FILE_LOCATION) +
                                        strlen("/logfile.") + 8);

               sprintf (temp_log_file, "%s/logfile.%d%c", FORK_LOG_FILE_LOCATION, getpid(),'\0');

               /* Open log file */
               int log = creat(temp_log_file, 0777);
               /* Redirect stdout to log file */
               close(1);
               dup(log);
               /* Redirect stderr to log file */
               close(2);
               dup(log);

               syslog(LOG_ERR, "Opening up log file %s\n", temp_log_file);

               free (temp_log_file);

               close (server_sockets_that_parent_is_listening_on);

               execvp ("jazzy_program", pArguments); 

         }

         pthread_exit (NULL);

         return NULL;
    }

我查看了这段代码,我看不出为什么我会做一个 fork 而不是一个 execvp——所以我想到的唯一场景是多个线程被执行并且它们都调用 fork + execvp。这有时会导致我的主程序运行两个副本。

【问题讨论】:

  • 您提供的代码不足以诊断或重现您所询问的问题,但我已经回答了一些想法。

标签: c multithreading pthreads exec fork


【解决方案1】:

如果execvp因任何原因失败(可能是进程太多、内存不足等),你无法处理错误;相反,线程的分叉副本继续运行。在此过程中调用 pthread_exit(或任何非异步信号安全)函数具有未定义的行为,因此它可能无法正确退出,而是挂起或执行一些意外的操作。发生这种情况时,您应该始终检查 exec 故障并立即检查 _exit(1) 或类似情况。此外,虽然这可能不是您的问题,但在多线程进程中分叉后调用 malloc 是不安全的,因为它是非异步信号安全的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多