首页 > 解决方案 > 使用 fork() 和 wait() 进行并行处理以完成进程

问题描述

我正在尝试创建某种“minishell”。但特殊因素是用户可以选择他的命令是否应该在后台处理。用户可以使用&命令行末尾的字符来确定是否应该在后台处理。

例子:

/tmp > date
Tue Apr 27 09:53:32 CEST 2021

/tmp > sleep 10                       // have to wait to be able to create a command again

/tmp > date
Tue Apr 27 09:56:33 CEST 2021

/tmp > sleep 10 &                    // sleep is processing in the background (don't have to wait)
[28727]                              // printing PID 

/tmp > ps
PID TT STAT TIME COMMAND
96440 s000 S 0:00.04 -bash
97144 s000 S+ 0:00.00 minishell.exe
28727 s000 S+ 0:00.00 sleep 10

/tmp > date
Process 28727 done (sleep 20)        // notify the user that the process is done
Tue Apr 27 10:12:38 CEST 2021

一切都运行良好,直到后台进程完成。命令行/shell 布局无法按预期工作。我没有为要输入的下一个命令打印我的计算机名称和文件路径:

computername@miniShell:/mnt/c/Users/name/desktop/minishell$ sleep 10 &
[28727]
//...
// after 10 sec
computername@miniShell:/mnt/c/Users/name/desktop/minishell$ ps
computername@miniShell:/mnt/c/Users/name/desktop/minishell$   PID TTY          TIME CMD
28648 pts/1    00:00:00 bash
28722 pts/1    00:00:00 minishell.exe
28730 pts/1    00:00:00 ps
date  // not getting computer name and path printed
computername@miniShell:/mnt/c/Users/name/desktop/minishell$ Mon Apr 26 17:44:36 CEST 2021
date // next command-line without computer-name and path...
//...

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pwd.h>
#include <cstring>
#include <string>
#include <vector>

using namespace std;


bool isBackground(char* string){
    char* c;
    int index;
    
    if(c = strchr(string, '\0'))
        index = (int)(c - string);
    
    for(int i = (index-1); i>=0; i--){        
        if((string[i] == '&') && (string[i-1] == ' '))
            return true;
        
        if((string[i] != ' '))
            return false;
    }
    return false;
}
 


int main(int argc, char * argv[]){
    
    int childPid;
    int tempPid;
    int status;
    char cwd[256];
    char input[256];
    char inputCopy[256];
    char *command;
    char *parameters[60];
    bool background = false;
    bool normalState = true;
    
    while(1) {
        
        //return user-info and current working directory if not background
        getcwd(cwd, sizeof(cwd));
        printf("%s@miniShell:%s$ ", getpwuid(getuid())->pw_name, cwd);

        //read command and parameters
        fgets(input, 256, stdin);
        command = strchr(input, '\n');

        //replace/delete /n-char if found
        if(command){
            *command = '\0';
        }

        //exit exception
        if(strncmp(input, "exit",4)==0){
            exit(0);
        }

        // determine if background processing is requested
        // delete trailing &
        if(background = isBackground(input)){
            command = strchr(input, '&');
            *command = '\0';
            strncpy(inputCopy, input, 256);
        }

        // cd exception
        if(strncmp(input, "cd ",3)==0){
            strtok(input, " ");
            command = strtok(NULL, "\0");
            if(chdir(command) != 0){
                perror("Error while changing directory. Please try again!");
            }
            continue;
        }

        if ((childPid = fork()) == -1) {
            fprintf(stderr,"can't fork\n");
            exit(0);
        }else if (childPid == 0) { /* child process*/
            command = strtok(input, " ");
            parameters[0] = command;
            int i = 1;
            while((parameters[i] = strtok(NULL, " ")) != NULL){
                i++;
            }
            if(execvp(command, parameters) < 0){
                cout << command << ": command not found!" << endl;
            }
            exit(0);
        } else { /* parent process */
        if(background){
            tempPid = childPid;
            cout << "[" << childPid << "]" << endl;
            continue;
        }
        //wait(&status);

        int waited;
        if((waited = wait(&status)) == tempPid){
            cout << "Process " << waited << " done (" << inputCopy << ")" << endl;
            normalState = false;
        }

        } /* endif parent */
    } /* end while forever */
    return 0;
}

标签: c++shellunixforkwait

解决方案


推荐阅读