主要过程 - > pthread - > fork + execvp

时间:2014-10-17 04:13:02

标签: c multithreading pthreads exec fork

我看到一个奇怪的问题。

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

我意识到我的代码中有一个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。这有时会导致我的主程序的两个副本运行。

1 个答案:

答案 0 :(得分:1)

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