时间由execv调用的程序的持续时间

时间:2018-09-29 19:52:09

标签: c time execv

我正在制作一个使用fork和execv并行运行其他程序的C程序。

我似乎无法计时execv调用的程序的执行时间,因为新进程在该程序完成运行后立即消失。另一个麻烦是无法使用父进程来等待子进程完成(我正在使用waitpid),因为我需要父进程执行其他一些工作,而不是等待子进程完成。

所以我的问题是:有没有一种方法可以在不使用辅助fork,pthread或文本文件的情况下测量execv调用的持续时间?

提前谢谢

1 个答案:

答案 0 :(得分:2)

您的父进程知道它何时发出fork()系统调用。这并不是execv进程开始运行的确切时间,因为execv()系统调用会花费一些时间,但是将这段时间包含在计数中并不是完全不合理的。如果您接受该限制,则只需将开始时间记录为调用fork()的时间。

当孩子终止时,父母将收到SIGCHLD信号。 SIGCHLD的默认操作是忽略它,但是您可能仍要更改它。如果将信号处理程序附加到SIGCHLD,则可以在该信号处理程序中调用waitpid(带有WNOHANG选项),直到收到所有终止子级的通知为止。对于每个通知,您都将通知时间记录为流程的结束时间。 (同样,如果系统处于重负载下,信号可能会从终端处滞后,从而导致您的时间度量不准确。但是在大多数情况下,它将是准确的。)

很明显,父级需要跟踪多个子进程。因此,您需要使用孩子的PID来为这些值编制索引。

现在每个子进程都有开始时间和结束时间。

但是有一个小问题。您不能将开始时间附加到子进程的PID上,直到fork()调用返回到父进程为止。但是,很可能fork()调用将返回到子级,并且子级将调用execv(),并且execv()的进程将在fork()调用返回给父级之前全部终止。 (说实话。)

因此SIGCHLD处理程序可能会收到有关终止其开始时间尚未记录的进程的通知。

这很容易解决,但是当您这样做时,您需要考虑到信号处理程序无法分配内存的事实。因此,如果要将开始时间和结束时间信息记录在动态分配的存储中,则需要在信号处理程序运行之前已分配存储。

所以代码看起来像这样:

1. Allocate storage for a new process times table entry
   (PID / start time / end time / status result). Set all
   fields to 0 to indicate that the entry is available.
2. Recall the current time as start_time (a local variable,
   not the table entry).
3. Fork()
4. (Still in the parent). Using an atomic compare-and-swap
   (or equivalent), set the PID of the table entry created
   in step 1 to the child's PID. If the entry was 0 (and is
   now the PID) or if the entry was already the PID, then
   continue to step 6.
5. If the entry has some other non-zero PID, find an empty entry
   in the table and return to step 4.
6. Now record the start time in the table entry. If the table entry
   already has an end time recorded, then the signal handler already
   ran and you know how long it took and what its return status is.
   (This is the case where the child terminated before you got to
   step 4.) You can now report this information.

在SIGCHLD信号处理程序中,您需要执行以下操作:

For each successful call to waitpid():
1. Find the entry in the child process information table whose PID
   corresponds to the PID returned by waitpid(). If you find one,
   skip to step 4.
2. Find an empty entry in the child process information table.
   Note that the signal handler cannot be interrupted by the main
   program, so locking is not required here.
3. Claim that entry by setting its PID field to the PID returned by
   waitpid() above.
4. Now that you have an entry, record the end time and return status
   information in the table entry. If the table entry existed
   previously, you need to put the entry on a notification queue
   so that the main process can notify the user. (You cannot call
   printf in a signal handler either.) If the table entry didn't
   exist before, then the main process will notice by itself.

您可能必须绘制一些图表才能使自己确信上述算法是正确的并且没有竞争条件。祝你好运。

此外,如果您以前没有做过任何事情,则需要阅读一下:-)

  • waitpid()。请特别注意用于提取状态信息的宏。

  • sigaction()。如何为信号分配处理函数。如果您仍然觉得这很希腊,请从signal(7)或Unix编程教科书中的相关章节开始。

  • Race conditions (from Wikipedia)

  • Compare and Swap (on Wikipedia)。 (不要使用他们的示例代码;它不起作用。GCC有一个built-in extension,它可以在任何有支持该方法的体系结构上实现原子比较和交换。我知道该部分已标记为旧版,您< em>应该在下一节__atomic中使用更复杂的功能,但是在这种情况下,默认值是可以的。但是,如果您使用__atomic_compare_exchange_n,请使用荣誉。)