C++ C语言的背景工作(在玩具壳中实现)
我想让它成为这样,当一个用户附加了一个命令后,它将在后台执行。出于某种原因,如果我正常执行命令,它会等待,如果我在后台执行命令,它会工作,但如果我正常执行命令,它不会等待。我肯定我只是做错了一些小事。任何想法:C++ C语言的背景工作(在玩具壳中实现),c++,c,c++11,C++,C,C++11,我想让它成为这样,当一个用户附加了一个命令后,它将在后台执行。出于某种原因,如果我正常执行命令,它会等待,如果我在后台执行命令,它会工作,但如果我正常执行命令,它不会等待。我肯定我只是做错了一些小事。任何想法: void executeSystemCommand(char *strippedCommand, char *background, int argc, char **args) { char pathToExecute[80]; // Check if comman
void executeSystemCommand(char *strippedCommand, char *background, int argc, char **args) {
char pathToExecute[80];
// Check if command will be executed in the background
int shellArgs;
bool bg;
if (!strcmp(background, "-")) {
bg = true;
shellArgs = argc -1;
} else {
bg = false;
shellArgs = argc;
}
// Save the linux commands in a new array
char *executableCommands[shellArgs+1];
int j;
for (j = 0; j < shellArgs+1; j++) {
executableCommands[j] = args[j];
}
executableCommands[shellArgs] = NULL;
// Check the $PATH
const char delimiters[] = ":";
char *token, *cp;
char *forLater;
int count = 0;
char *path;
path = getenv("PATH");
// All of this just breaks up the path into separate strings
cp = strdup(path);
forLater = strdup(path);
token = strtok (cp, delimiters);
while ((token = strtok (NULL, delimiters)) != NULL) {
count++;
}
char **argv;
int size = count+1;
argv = (char**) malloc (size);
count = 0;
token = strtok (forLater, delimiters);
argv[0] = (char*) malloc (50);
argv[0] = token;
strcpy(argv[0],token);
while ((token = strtok (NULL, delimiters)) != NULL) {
count++;
argv[count] = (char*) malloc (50);
argv[count] = token;
}
// This goes through the path to see if the linux command they entered
// Ex: sleep exists in one of those files and saves it to a var
int i;
bool weHaveIt = false;
int ac;
for (i = 0; i < count; i++) {
char str[80];
strcpy(str, argv[i]);
strcat(str, "/");
strcat(str, args[0]);
ac = access(str, F_OK);
if (ac == 0) {
weHaveIt = true;
strcpy(pathToExecute, str);
break;
}
}
if (!weHaveIt) {
printf("That is not a valid command. SORRY!\n");
return;
}
executableCommands[0] = pathToExecute;
int status;
// Get the array for
// If user wants command to be a background process
if (bg) {
int background_process_id;
pid_t fork_return;
fork_return = fork();
if (fork_return == 0) {
background_process_id = getpid();
addJobToTable(strippedCommand, background_process_id);
setpgid(0, 0);
execve(executableCommands[0], executableCommands, NULL);
exit(0);
} else {
return;
}
} else {
int background_process_id;
pid_t fork_return;
fork_return = fork();
if (fork_return == 0) {
background_process_id = getpid();
status = execve(executableCommands[0], executableCommands, NULL);
exit(0);
} else {
wait(&status);
return;
}
}
}
void executeSystemCommand(char*strippedCommand,char*background,int argc,char**args){
字符路径执行[80];
//检查命令是否将在后台执行
int shellArgs;
布尔bg;
如果(!strcmp(背景,“-”){
bg=真;
shellArgs=argc-1;
}否则{
bg=假;
shellArgs=argc;
}
//将linux命令保存在新数组中
char*executableCommands[shellArgs+1];
int j;
对于(j=0;j
当父进程退出时,使用fork()创建的每个子进程都将退出
if (fork_return == 0) {
/* child process, do stuff */
} else {
/* parent process, exit immediately */
return;
}
解释
生成一个新进程作为当前进程(父进程)的子进程。每当类Unix操作系统中的进程终止时,其所有子进程也将终止。如果它们自己有子进程,那么它们也会被终止
解决方案
在大多数shell中,如果在行尾添加一个符号,则可以在后台启动进程:
myApplication arg1 arg2 arg3 ... argN &
我的应用程序arg1 arg2 arg3。。。argN&当父进程退出时,使用fork()
创建的每个子进程都将退出
if (fork_return == 0) {
/* child process, do stuff */
} else {
/* parent process, exit immediately */
return;
}
解释
生成一个新进程作为当前进程(父进程)的子进程。每当类Unix操作系统中的进程终止时,其所有子进程也将终止。如果它们自己有子进程,那么它们也会被终止
解决方案
在大多数shell中,如果在行尾添加一个符号,则可以在后台启动进程:
myApplication arg1 arg2 arg3 ... argN &
我的应用程序arg1 arg2 arg3。。。argN&为第三个作业调用wait
会立即返回,因为第二个作业已完成,正在等待处理(也称为“僵尸”)。您可以检查wait(&status)
的返回值,该值是已退出的进程的PID,并确保它是您正在等待的进程。如果不是,只需再次调用等待
或者使用等待特定进程的waitpid
:
/* Wait for child. was: wait(&status) */
waitpid(fork_return, &status, 0);
如果这样做,您应该为SIGCHLD
实现一个信号处理程序来处理已完成的后台作业,以防止“僵尸”子进程的累积
除此之外,在后台作业案例中,fork()
的分支返回0您已经在新进程中,因此对addJobToTable
的调用发生在错误的进程中。此外,还应检查所有调用的返回值;否则,有些事情可能会失败,而你却不知道。因此,在后台运行作业的代码应该更像这样:
if (fork_return == 0) {
setpgid(0, 0);
if (execve(executableCommands[0], executableCommands, NULL) == -1) {
perror("execve");
exit(1);
}
} else if (fork_return != -1) {
addJobToTable(strippedCommand, fork_return);
return;
} else {
perror("fork"); /* fork failed */
return;
}
对第三个作业的wait
调用会立即返回,因为第二个作业已完成,正在等待处理(也称为“僵尸”)。您可以检查wait(&status)
的返回值,该值是已退出的进程的PID,并确保它是您正在等待的进程。如果不是,只需再次调用等待
或者使用等待特定进程的waitpid
:
/* Wait for child. was: wait(&status) */
waitpid(fork_return, &status, 0);
如果你这样做,你应该