- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
首先让我说这里有很多问题。
我论文的其中一项任务要求我编写一个程序来执行一个子程序,如果它的运行时间(不是 wall-time 而是 user+sys )超过特定值或者它的 RAM 消耗是超过另一个指定值。
虽然我还没有弄清楚RAM部分。我用 setitmer 和 ITIMER_PROF 信号消磨时间。 (因为 ITIMER_PROF 收集实际的 CPU 使用率,而不是设置一个时间起点,然后计算 x 时间量)
我使用 setitimer 的原因是我需要的精度低于秒级。 (例如,在 1.75 秒(1750000 微秒)后终止进程。setrlimit 方法只有一秒。
问题 1 为什么在父进程中设置带有 ITIME_PROF 的 setitimer 不工作? child 的 CPU/系统调用不是由它收集的吗?
childPID = fork();
if (childPID == -1){
printf( "Puff paff ... fork() did not work !\n" );
exit(1);
}
// Child
if(childPID == 0) {
execvp(args[0], args);
exit(1);
}
// Parent
else{
// Using a ITIMER_PROF inside the parent program will not work!
// The child may take 1 hour to execute and the parent will wait it out!
// To fix this we need to use a ITIMER_REAL ( wall-time ) but that's not an accurate measurement
struct itimerval timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 500000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 500000;
setitimer ( ITIMER_PROF, &timer, NULL);
int status;
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", cPID, WEXITSTATUS(status) );
}
}
问题 2 为什么这有效!? execvp 不会覆盖所有函数(timeout_sigprof、main 和任何其他函数)吗?难道就不能有人在子程序中捕捉到信号并取代原来的功能吗?
void timeout_sigprof( int signum ){
fprintf(stderr, "The alarm SIGPROF is here !\nThe actual pid: %d\n", getpid());
//TODO: Write output and say the child terminated with
// ram or time limit exceeded
exit(105); // Note the 105 !
}
childPID = fork();
if (childPID == -1){
printf( "Puff paff ... fork() did not work !\n" );
exit(1);
}
// Child
if(childPID == 0) {
//
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timeout_sigprof;
sigaction (SIGPROF, &sa, NULL);
struct itimerval timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 250000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 250000;
setitimer ( ITIMER_PROF, &timer, NULL);
execvp(args[0], args);
exit(1);
}
// Parent process
else {
// Waiting for the child
int status;
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", cPID, WEXITSTATUS(status) );
}
exit(0);
}
问题 3 为什么放在这里的 dup2 真的可以工作,让 child 的输入/输出被重定向?
childPID = fork();
if (childPID == -1){
printf( "Puff paff ... fork() did not work !\n" );
exit(1);
}
// Child
if(childPID == 0) {
// Redirect all I/O to/from a file
int outFileId = open("output", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
// Redirect the output for the CHILD program. Still don't know why it works.
dup2(outFileId, 1)
// No idea why these dup2's work ! As i close the file descriptors here ?!
close(outFileId);
execvp(args[0], args);
exit(1);
}
// Parent process
else {
// Waiting for the child
int status;
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", cPID, WEXITSTATUS(status) );
}
exit(0);
}
这是我编写的代码,它仅在程序运行了 X 时间 (x = 500ms) 后才运行并终止该程序。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
volatile pid_t childPID;
// This function should exist only in the parent! The child show not have it after a exec* acording to :
// The exec() family of functions replaces the current process image with a new process image.
void timeout_sigprof( int signum ){
fprintf(stderr, "The alarm SIGPROF is here !\nThe actual pid: %d\n", getpid());
//TODO: Write output and say the child terminated with a ram or time limit exceeded
exit(105); // Note the 105 !
}
int main(int argc, char *argv[]) {
int cstatus;
pid_t cPID;
char *args[2];
args[0] = "/home/ddanailov/Projects/thesis/programs/prime/prime";
args[1] = NULL; // Indicates the end of arguments.
// Handle the SIGPROF signal in the function time_handler in both the child and
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timeout_sigprof;
sigaction (SIGPROF, &sa, NULL);
childPID = fork();
if (childPID == -1){
printf( "Puff paff ... fork() did not work !\n" );
exit(1);
}
// Child
if(childPID == 0) {
struct itimerval timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 250000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 250000;
setitimer ( ITIMER_PROF, &timer, NULL);
// Redirect all I/O to/from a file
int outFileId = open("output", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
// int inFileId = open("input");
// Redirect the output for the CHILD program. Still don't know why it works.
//dup2(inFileId, 0);
dup2(outFileId, 1);
//dup2(outFileId, 2);
// No idea why these dup2's work ! As i close the file descriptors here ?!
close(outFileId);
close(inFileId);
execvp(args[0], args);
exit(1);
}
// Parent process
else {
// Waiting for the child
int status;
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", cPID, WEXITSTATUS(status) );
}
exit(0);
}
return 0;
}
任何帮助/解释将不胜感激!
先谢谢大家
前
最佳答案
Why doesn't the setitimer with ITIME_PROF work when it's set in the parent process ? The CPU / System calls for the child are not collected by it ?
不,他们不是。与 ITIME_PROF 相关的计时器仅在设置了计时器的进程正在执行时递减,或者当系统调用代表它执行时,而不是在子进程正在执行时递减。
这些信号通常由分析工具使用,分析工具包含在您链接到您尝试分析的程序的库中。
但是:您可能不需要将信号发送到父进程。如果您的目标是在程序超过允许的使用量后终止程序,那么让它接收 SIGPROF 并退出(如我对下面 Q2 的回答所示)。然后,在 waitpid
返回并且您检测到程序由于 SIGPROF 退出后,您可以通过调用 times
找出 child 实际使用的时间量。或 getrusage
.
唯一的缺点是子程序可以通过在 SIGPROF 上设置它自己的信号处理程序来破坏这个过程。
Why does this WORK!? Doesn't the execvp overwrite all the functions ( timeout_sigprof, main and any other)? And couldn't someone potentially catch the signal in the child program and supersede the original function ?
事实并非如此,或者至少不是您所想的那样。正如您所说,您在父进程中安装的信号处理程序被 execvp 加载的新图像所取代。
它似乎起作用的原因是如果新程序没有为 SIGPROF 设置信号处理程序,那么当该信号被发送到进程时它将终止。回想一下,任何发送到该进程尚未设置处理程序或明确决定忽略的进程的信号都将导致该进程终止。
如果 execvp 正在执行的程序确实为 SIGPROF 设置了信号处理程序,则它不会终止。
更新
看到你的评论,我想我最好试试你的程序。我在 waitpid 之后的 if 语句中添加了另一个分支,如下所示:
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", childPID, WEXITSTATUS(status) );
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "Process pid=%d received signal %d\n",childPID,WTERMSIG(status));
}
当我运行它时,我看到以下内容:
$ ./watcher
Process pid=1045 received signal 27
这证实了我上面所说的。我没有看到字符串“The alarm SIGPROF is here !”打印出来,我确实在 parent 身上看到一个迹象表明 child 被信号 27 杀死,这是 SIGPROF。
我只能想到您会看到信号处理程序执行的一种情况,那就是如果计时器设置得太低以至于它在 execv 实际设法加载新图像之前触发。不过,这看起来不太可能。
另一种可能是您无意中在目标程序中安装了相同的信号处理程序(复制粘贴错误?)。
Why does the dup2 placed here actually work and let's the child's input / output to be redirected ?
根据代码中的注释,我假设您的意思是“即使我在 dup2 之后立即关闭了原始文件描述符,为什么它仍然有效?”
dup2将旧的FD复制到新的FD中,所以执行后:
dup2(outFileId, 1);
您有两个文件描述符引用相同的文件描述:一个包含在变量 outFileId 中,另一个是 FD 1(即标准输出)。另请注意,原始标准输出将被此操作关闭。
文件描述符就像对底层文件描述数据结构的引用,代表打开的文件。调用dup2后,有两个文件描述符指向同一个文件描述。
close
的手册页说:
If fd is the last file descriptor referring to the underlying open file description (see open(2)), the resources associated with the open file description are freed
所以它按它应该的方式工作:你仍然有一个打开的 FD,FD 1 (stdout),新的子进程可以写入它。
关于c - 为什么 setitimer 和 dup2 在 execvp 之后为子进程工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24885081/
POSIX 系统公开了一系列 exec 函数,这些函数允许将可能不同的东西加载到当前进程中,保持打开的文件描述符、进程标识符等。 这可以出于多种原因完成,在我的例子中,这是自举——我想更改我自己进程的
我有一个用 c 编写的程序,它使用 execvpe(3) 函数,并且我设置了一行以包含必需的头文件: #include 我使用以下命令编译此文件... gcc foo.c -o foo ...仅收到
我在 C 中有一个函数,它创建一个子进程并使其运行 execvp。 int Execute(char **arg) { pid_t pid; int status; if ((
我正在使用 C 编写一个非常基本的 UNIX shell。在这个项目中,我试图使用 fork() 和 execvp() 来执行实际的 shell命令。我遇到了一个问题,它似乎可以很好地处理具有单个参数
我无法获得使用 execvp 调用的程序的完整输出。在这里,我基本上是在尝试用一个可以过滤输入和输出的程序来包装任何程序: #define BUF_SIZ 8192 int main(int argc
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我正在尝试用 c 语言创建一个 shell,当前正在尝试 ls 命令,但子进程总是返回 execvp 无法工作。这是函数。首先,我使用 exec 获取我所在的路径和从 stdin 获取的命令,这就是为
我正在开发这个程序,使用系统调用 execvp() 和 fork() 来运行通过命令行参数给出的 shell 命令。这里 arglist 是一个二维数组,其中包含命令名称及其参数列表。我将命令名称作为
我尝试使用 execvp 创建一个作为参数给出的存储库。但我遇到了一些无法在以下代码中解决的段错误(核心转储): #include //mkdir #include #include //p
我正在尝试使用 execvp 对文件进行排序,这是我的代码。 char *argv1[]={ "sh", "-c", "sort input.txt > output.txt", NULL }; 问题
我正在c中测试execvpe(),我尝试了下面的代码,这导致错误“函数‘execvpe’的隐式声明在C99 [-Wimplicit-function-declaration]中无效”。 #includ
我有以下代码: int main(int argc, char *argv[]) { int i, a=9; int length = 0; c
我正在使用 execvp() 运行一些系统调用。程序对于有效命令非常有效,对于任何不存在的命令则失败,这是完美的。该程序是,当我在需要额外参数(如 cat)的命令上使用 execvp() 并且我不提供
用户将读取一行,我将保留第一个单词作为 execvp 的命令。 假设他将输入“cat file.txt” ...命令将为 cat 。但我不知道如何使用这个execvp(),我读了一些教程但仍然没有明白
我正在用 C 编程编写一个正在运行的 shell 脚本。我读过有关 exec 函数的内容,虽然不太了解,但我读过一个像这样使用 execvp 的示例 execvp(*argv, argv) ; /*
这是我的输入函数: int i,j,n,len,c; char *buffer = 0; size_t bufsize = 0; ssize_t characters;
我正在尝试编写一个程序,该程序将 fork ,然后打开一个文件并执行它。它应该执行的文件称为子文件,并且它已经被编译。当我输入 ./child 时,它就会运行。但是,当我运行该程序时,它不会执行子程序
所以我有一个 C 程序,它接受命令输入,但偶尔我似乎会遇到某种内存错误。 我如何读取输入: static void parseLine(char* commandLine, Sequence* seq
我尝试在终端中传递命令行参数“ls -l/user/myuser”并在主目录中执行 execvp。 但不知何故,当我调试代码时,它给了我这个错误。 int main(int argc, char *a
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
我是一名优秀的程序员,十分优秀!