c - 计算 execv 调用的程序的持续时间

标签 c time execv

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

我似乎无法计算 execv 调用的程序的执行持续时间,因为新进程在该程序运行完毕后立即终止。另一个复杂之处是无法使用父进程等待子进程完成(我正在使用 waitpid),因为我需要父进程做一些其他工作而不是等待子进程完成。

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

提前谢谢

最佳答案

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

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

显然,父进程需要跟踪多个子进程。因此,您需要使用子进程的 PID 来为这些值建立索引。

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

不过有一个小问题。在 fork() 调用返回到父进程之前,您无法将开始时间附加到子进程的 PID。但是完全有可能 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,它在任何支持它的体系结构上实现原子比较和交换。我知道该部分被标记为遗留,并且您 应该在下一节__atomic中使用更复杂的函数,但在这种情况下,默认值就可以了。但如果您使用__atomic_compare_exchange_n,那就太好了。)

关于c - 计算 execv 调用的程序的持续时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52572005/

相关文章:

c++ - 如何将后台运行的子进程调到前台

c - C execve() 函数是否终止子进程?

c - 丢失的 ;在 'type' 错误之前

c - 特定地址处的动态结构数组

java - 在 Java 中记录任务完成时间的智能解决方案是什么?

mysql - 当我们有 n 次在 00 :00:00 format 中时,如何在 mysql 中添加时间列表

c++ - 非法参数 Execv() Unix C++

有人可以解释一下以下代码的输出吗

c - 使用不同功能时出现段错误

php - 使用时间戳和时区