如何在用户输入时终止 waitpid?
How to terminate waitpid on user input?
我正在使用 C 语言开发一个基于 ncurses 的文件管理器。问题是一些子进程可能需要一些时间才能完成,直到发生这种情况它仍然卡住,因为 waitpid
。
我不能使用 WNOHANG
标志,因为下一个代码块取决于子进程的输出。
void getArchivePreview(char *filepath, int maxy, int maxx)
{
pid_t pid;
int fd;
int null_fd;
// Reallocate `temp_dir` and store path to preview file
char *preview_path = NULL;
allocSize = snprintf(NULL, 0, "%s/preview", cache_path);
preview_path = malloc(allocSize+1);
if(preview_path == NULL)
{
endwin();
printf("%s\n", "Couldn't allocate memory!");
exit(1);
}
snprintf(preview_path, allocSize+1, "%s/preview", cache_path);
// Create a child process to run "atool -lq filepath > ~/.cache/cfiles/preview"
pid = fork();
if( pid == 0 )
{
remove(preview_path);
fd = open(preview_path, O_CREAT | O_WRONLY, 0755);
null_fd = open("/dev/null", O_WRONLY);
// Redirect stdout
dup2(fd, 1);
// Redirect errors to /dev/null
dup2(null_fd, 2);
execlp("atool", "atool", "-lq", filepath, (char *)0);
exit(1);
}
else
{
int status;
waitpid(pid, &status, 0);
getTextPreview(preview_path, maxy, maxx);
free(preview_path);
}
}
在这种情况下,如果用户决定转到其他文件,我想继续执行程序的其余部分。我可以通过什么方式更改程序的架构?
如果我正确理解了问题,那么您希望在完成 child 或任何用户输入时取消阻止 parent。
正如 评论中所建议的那样,您可以处理 SIGCHLD
和另一个信号 SIGUSR1
。 SIGUSR1
将在您获得用户输入时引发。以下是同时处理 SIGCHLD
和 'SIGUSR1' 的示例。如果使用输入任何数字,则它会将 SIGUSR1
提高到 parent 和 parent kill
child。否则 child 将在退出时加注 SIGCHLD
。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int raised_signal = -1;
static void cb_sig(int signal)
{
if (signal == SIGUSR1)
raised_signal = SIGUSR1;
else if (signal == SIGCHLD)
raised_signal = SIGCHLD;
}
int main()
{
int pid;
int i, a;
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = cb_sig;
if (sigaction(SIGUSR1, &act, NULL) == -1)
printf("unable to handle siguser1\n");
if (sigaction(SIGCHLD, &act, NULL) == -1)
printf("unable to handle sigchild\n");
pid = fork();
if (pid == 0) {
/* child */
for (i = 0; i < 10; i++) {
sleep(1);
printf("child is working\n");
}
exit(1);
} else {
/* parent */
if (-1 == scanf("%d", &a)) {
if (errno == EINTR)
printf("scanf interrupted by signal\n");
} else {
raise(SIGUSR1);
}
if (raised_signal == SIGUSR1) {
printf("user terminated\n");
kill(pid, SIGINT);
} else if (raised_signal == SIGCHLD) {
printf("child done working\n");
}
exit(1);
}
return 0;
}
我正在使用 C 语言开发一个基于 ncurses 的文件管理器。问题是一些子进程可能需要一些时间才能完成,直到发生这种情况它仍然卡住,因为 waitpid
。
我不能使用 WNOHANG
标志,因为下一个代码块取决于子进程的输出。
void getArchivePreview(char *filepath, int maxy, int maxx)
{
pid_t pid;
int fd;
int null_fd;
// Reallocate `temp_dir` and store path to preview file
char *preview_path = NULL;
allocSize = snprintf(NULL, 0, "%s/preview", cache_path);
preview_path = malloc(allocSize+1);
if(preview_path == NULL)
{
endwin();
printf("%s\n", "Couldn't allocate memory!");
exit(1);
}
snprintf(preview_path, allocSize+1, "%s/preview", cache_path);
// Create a child process to run "atool -lq filepath > ~/.cache/cfiles/preview"
pid = fork();
if( pid == 0 )
{
remove(preview_path);
fd = open(preview_path, O_CREAT | O_WRONLY, 0755);
null_fd = open("/dev/null", O_WRONLY);
// Redirect stdout
dup2(fd, 1);
// Redirect errors to /dev/null
dup2(null_fd, 2);
execlp("atool", "atool", "-lq", filepath, (char *)0);
exit(1);
}
else
{
int status;
waitpid(pid, &status, 0);
getTextPreview(preview_path, maxy, maxx);
free(preview_path);
}
}
在这种情况下,如果用户决定转到其他文件,我想继续执行程序的其余部分。我可以通过什么方式更改程序的架构?
如果我正确理解了问题,那么您希望在完成 child 或任何用户输入时取消阻止 parent。
正如 SIGCHLD
和另一个信号 SIGUSR1
。 SIGUSR1
将在您获得用户输入时引发。以下是同时处理 SIGCHLD
和 'SIGUSR1' 的示例。如果使用输入任何数字,则它会将 SIGUSR1
提高到 parent 和 parent kill
child。否则 child 将在退出时加注 SIGCHLD
。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int raised_signal = -1;
static void cb_sig(int signal)
{
if (signal == SIGUSR1)
raised_signal = SIGUSR1;
else if (signal == SIGCHLD)
raised_signal = SIGCHLD;
}
int main()
{
int pid;
int i, a;
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = cb_sig;
if (sigaction(SIGUSR1, &act, NULL) == -1)
printf("unable to handle siguser1\n");
if (sigaction(SIGCHLD, &act, NULL) == -1)
printf("unable to handle sigchild\n");
pid = fork();
if (pid == 0) {
/* child */
for (i = 0; i < 10; i++) {
sleep(1);
printf("child is working\n");
}
exit(1);
} else {
/* parent */
if (-1 == scanf("%d", &a)) {
if (errno == EINTR)
printf("scanf interrupted by signal\n");
} else {
raise(SIGUSR1);
}
if (raised_signal == SIGUSR1) {
printf("user terminated\n");
kill(pid, SIGINT);
} else if (raised_signal == SIGCHLD) {
printf("child done working\n");
}
exit(1);
}
return 0;
}