在C语言中将进程置于后台

5

我正在深入研究使用C&创建后台作业。为了使其正常工作,我需要实现一个非阻塞的waitpid。我知道这一点。此外,我已经捕获了如果在命令行末尾输入&的情况。我只是不确定如何确切地将进程发送到后台作业,并将其实现为在另一个提示正在提示下一个命令时执行。
任何帮助都会很有用,谢谢。

    struct bgprocess{
        int pid;
        struct bgprocess * next;
        struct bgprocess * prev;    
    };

    struct bgprocess * bgprocess1;
    bgprocess1 = malloc(sizeof(struct bgprocess));
    bgprocess1->prev = NULL;
    bgprocess1->next = NULL;
    bgprocess1->pid = NULL;

    struct bgprocess * current;
    current = bgprocess1;

    do{
        int bgreturn = 0;
        while (current != NULL){
            if (waitpid(current->pid, &bgreturn, WNOHANG)){
                printf("Child exited");
                current->prev->next = current->next;
                current->next->prev = current->prev;
                current->prev = NULL;
                current->next = NULL;
                free(current);                  
            }
        current = current->next;    
        }
        if (end){
            int pid = fork();
            if (pid < 0){
                exit(1);            
            }       
            if (pid) {
                execvp(args[0], args);          
                exit(0);            
            }

            struct bgprocess * newNode;
            newNode = malloc(sizeof(struct bgprocess));
            newNode->pid = pid;
            newNode->next = NULL;

            if (current->next == NULL){
                current->next = newNode;        
            }
            while (1){
                if (current->next == NULL){
                    current->next = newNode;
                }           
                current = current->next;
            }

        }
    }
    while (current != NULL);

    int bgreturn = 0;
    while (current != NULL){
        if (waitpid(current->pid, &bgreturn,0)){
            printf("Child exited");
            current->prev->next = current->next;
            current->next->prev = current->prev;
            current->prev = NULL;
            current->next = NULL;
            free(current);  
        }
        current = current->next;
    }
    }

好的,我已经在继续研究这个问题,我认为我可能开始理解了。我仍然有一些语法错误,不知道如何修复,所以我可能会使用gdb或其他工具,除非有人能指出它们。我是正确地处理问题还是完全错误了?


你是否想要在C代码中后台执行外部Linux命令? - MOHAMED
可能是Waitpid等效的超时?的重复问题。 - s4y
你显然没有包含所有的内容。例如,end是什么?pathlist是什么?为什么要分叉十个子进程?当似乎你实际上想让你的进程挂起并等待这些睡眠进程时,为什么要使用WNOHANG?你下面说它正在打印'ls'?在哪里?这里没有打印语句。 - FrankieTheKneeMan
从man页(我在我的回复中为您提供了链接,但您可以通过键入'man wait' 在系统上查找它):“ WNOHANG:如果没有子进程退出,则立即返回”-这意味着它不会等待,仅检查该子进程的情况。做自己一个快乐,总是从上到下阅读MAN页。它们写得很好。 - FrankieTheKneeMan
@Requiem,请贴出你的完整代码,如果你想得到更多的帮助。 - FrankieTheKneeMan
显示剩余10条评论
1个回答

11
听起来你正在实现一个shell。
只需使用fork创建一个子进程-这将是并发的。从那里,您可以使用exec*系列执行任何可执行文件,或者在子进程中运行C代码,而父进程则返回并提示获取更多信息(下一个命令等)。在循环顶部使用带有WNOHANG选项的wait检查已终止的子进程,然后再次(这次没有WNOHANG)在末尾检查其余子进程。
我必须鼓励您不要使它比实际情况更复杂。用普通英语(或您的母语或伪代码)写出您想要的内容,然后仅使用最少的巧妙将其转换为C代码。
(伪)代码:
struct child {
    int pid;
    struct child * next;
    struct child * prev;
}
struct child * children = null;
do {
    int return = 0;
    struct child * curr = children;
    while(curr != null){
        if(waitpid(curr->pid, &return, WNOHANG)){
            //Report child exited with return status 'return'
            //Remove child (linked list style)
         }
         curr = curr->next;
     }
     /* PROMPT, ETC */
     if ( doInBackground ){
         int pid = fork();
         if(pid <0 )exit(); //error
         if(pid){
             //Child
             execvp(processName, arrayOfArgs);
             //This should never get executed
             exit();
         }
         //Add pid (linked list style, again)
     }
}while(!exitCondition)

int return = 0;
struct child * curr = children;
while(curr != null){
    if(waitpid(curr->pid, &return, 0)){
        //Report child exited with return status 'return'
        //Remove child (linked list style)
    }
    curr = curr->next;
}

另外,我必须确保没有僵尸进程留下来,这就是为什么我认为需要使用waitpid的原因。 - user1642463
fork返回一个进程ID给父进程。维护一个子进程PID列表,当shell退出时,可以简单地等待它们中的每一个。在控制循环的顶部,只需使用wait和WNOHANG检查任何已终止的进程,以将它们从活动子进程PID列表中删除。 - FrankieTheKneeMan
我现在有些困惑,如果我发布我目前的代码,你能否了解我的思路?这样会有帮助吗? - user1642463
那实际上总是会有帮助的。但不要将其放在评论中 - 编辑您的原始问题。 - FrankieTheKneeMan
@Requiem - 添加了伪代码。请注意,在现实世界中,即使waitpid返回,也不意味着退出。请查看手册以获得更好的错误检查。 - FrankieTheKneeMan
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接