簡體   English   中英

Fork() 不會創建子項 - C

[英]Fork() does not create a child - C

我正在研究 Raspberry Pi 3B 上的操作系統項目。 我必須在 C 中實現一種流程管理器程序。 有一個主進程P必須處理進程P1 - P2 - P3 -...- PN的鏈表。 (這是一個過程鏈,意味着P1分叉P2P2分叉P3等等)。 該列表使用P1初始化, P的子元素作為其第一個元素。

在硬件層面上,分別有 4 個按鈕(1、2、3、4)和 4 個 LED,每對都由一個單獨的進程S管理。 這 4 個S進程也是主進程P的子進程,但不在鏈表中。 現在,每個按鈕都有在列表上執行的不同操作。

  • 按鈕 1 刪除列表中的第一個進程,並將所有后續進程向前移動一個 position。 通過轉移意味着從n 個進程中清空大小為n的列表,然后創建n-1並將其添加回來,以這種方式模擬僅刪除第一個進程P1 (它們確實是新進程)。
  • 按鈕 2 將新進程PN+1添加到列表中。
  • 按鈕 3 select 列表中的下一個進程(初始化列表時,默認選擇P1 )。
  • 按鈕 4 從列表中刪除選定的進程(按鈕 2 的故事相同,但僅移動了列表的選定部分)。

我已經正確實現了所有硬件部分, PS進程通過管道進行通信,因此不在這個問題的 scope 范圍內。 我還設法實現了按鈕 2 和 3,以便它們滿足要求。

關於如何實現按鈕 1,我已經堅持了一個多星期。

這是主要的。c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>
#include "linkedlist.h"
#include "M_process.h"
#include "S_process.h"

int main(int argc, char *argv[]) {
    const char BUTTONS[] = "FASD";
    const int N_OF_S = 4;
    int fd1[2], fd2[2];  // pipes (P to S) and (S to P) 
    pid_t s_processes[N_OF_S];
    int arg_index = 1;
    setup_pipes(fd1, fd2);

    pid_t pid;
    for (int i = 0; i < N_OF_S; i++) {
        pid = fork();
        if (pid < 0) {
            fprintf(stderr, "Error in forking process S%d\n", i);
            return -1;
        } else if (pid > 0) {
            arg_index += 2;
            s_processes[i] = pid;
        } else {
            close(fd1[1]);
            close(fd2[0]);
            char *p;
            long button, led;
            button = strtol(argv[arg_index], &p, 10);
            led = strtol(argv[arg_index + 1], &p, 10);
            s_fun((int) button, (int) led, BUTTONS[i], fd1, fd2);
            return 0;
        }
    }
    close(fd1[0]);
    close(fd2[1]);

    List list;
    List *p_list = &list;
    initialize_list(p_list);

    pthread_t t;
    pthread_create(&t, NULL, listen_input, p_list);

    process_buttons(p_list);

    for (int i = 0; i < N_OF_S; i++) {
        waitpid(s_processes[i], NULL, 0);
    }

    wait(NULL);

    return 0;
}

M_process.c (主進程P中使用的函數):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include "linkedlist.h"
#include "P_process.h"

int m_to_s[2];
int s_to_m[2];
int p_to_m[2];

void initialize_list(List *list) {
    int fd[2];
    pipe(fd);
    p_to_m[1] = fd[1];
    p_to_m[0] = fd[0];
    init_list(list);
    pid_t pid = fork();
    if (pid < 0) {
        fprintf(stderr, "Couldn't fork\n");
    } else if (pid == 0) {
        close(m_to_s[1]);
        close(s_to_m[0]);
        close(fd[0]);
        signal(SIGINT, term_handler);
        signal(SIGUSR1, fork_handler);
        p_listen(1, fd);
        close(fd[1]);
        exit(0);
    } else {
        close(fd[1]);
        append(list, pid, "00000000");
    }
}

void *listen_input(void *list) {
    char input;
    int reading = 1;
    while (reading) {
        scanf(" %c", &input);
        switch (input) {
            case 'q':
                reading = 0;
                for (int i = 0; i < 4; i++) {
                    write(m_to_s[1], &input, sizeof(char));
                }
                for (int i = size(list); i > 0; i--) {
                    kill(last_pid(list), SIGINT);
                    remove_last(list);
                }
                fprintf(stderr, "List deallocated.\n");
                break;
            case 'p':
                print_list(list);
                break;
            case 'h':
                fprintf(stderr, "Enter '\e[1;37mp\e[0m' to inspect the list or '\e[1;37mq\e[0m' to exit.\n");
                break;
            default:
                fprintf(stderr, "Command not found.\n");
                break;
        }
    }
    fprintf(stderr, "Goodbye!\n");
    pthread_exit(NULL);
}

int setup_pipes(int fd1[2], int fd2[2]) {
    if (pipe(fd1) < 0 || pipe(fd2) < 0) {
        fprintf(stderr, "Error in creating pipes\n");
        return -1;
    }
    m_to_s[1] = fd1[1];
    s_to_m[0] = fd2[0];
    return 0;
}

pid_t add_process(List *list, int n_of_processes) {
    if (n_of_processes > 0) {
        kill(last_pid(list), SIGUSR1);
        pid_t pid;
        read(p_to_m[0], &pid, sizeof(pid_t));
        char *p;
        p = id_generator(8);
        append(list, pid, p);
        add_process(list, n_of_processes - 1);
        return pid;
    }
    return 0;
}

void process_buttons(List *list) {
    char cmd;
    while (read(s_to_m[0], &cmd, sizeof(char)) != 0) {
        switch (cmd) {
            case 'F': {
                pid_t removed = first_pid(list);
                int to_add = size(list) - 1;
                for (int i = size(list); i > 0; i--) {
                    kill(last_pid(list), SIGINT);
                    remove_last(list);
                }
                initialize_list(list);
                add_process(list,to_add);
                fprintf(stderr, "(\e[1;31m-\e[0m) First process (\e[1;37m%d\e[0m) removed.\n", removed);
                break;
            }
            case 'A': {
                pid_t pid = add_process(list, 1);
                fprintf(stderr, "(\e[1;32m+\e[0m) Process \e[1;37m%d\e[0m [id: %s] appended to the list.\n", pid,
                        last_id(list));
                break;
            }
            case 'S': {
                select_next(list);
                fprintf(stderr, "(\e[1;33m*\e[0m) Next process (\e[1;37m%d\e[0m) selected.\n", selected_pid(list));
                break;
            }
            case 'D': {
                fprintf(stderr, "(\e[1;31m-\e[0m) Removed selected process (\e[1;37m%d\e[0m) from the list.\e[0m\n",
                        selected_pid(list));
                break;
            }
            default: {
                break;
            }
        }
    }
}

最后是 P_process.c (列表中進程 P 使用的函數):

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int fd[2];
int listen;

void p_listen(int l, int fd3[2]) {
    fd[0] = fd3[0];
    fd[1] = fd3[1];
    listen = l;
    while (listen) pause();
}

void fork_handler(int signo) {
    pid_t pid = fork();
    if (pid < 0) {
        fprintf(stderr, "Couldn't add another P");
    } else if (pid > 0) {
        write(fd[1], &pid, sizeof(pid_t));
    }
}

void term_handler(int signo) {
    listen = 0;
}

實際上,列表中的進程除了等待信號之外什么都不做,然后它們要么退出要么分叉。 鏈表在另一個文件中實現,你可以假設它的基本和通用功能。

我的實現背后的想法基本上如下:

  • 如果我需要添加一個進程PN+1 ,我向列表中的最后一個進程PN發送了一個SIGUSR1信號,該進程調用了fork_handler function。 PN分叉,通過 pipe 將PN+1的 pid 發送到主進程P ,主進程 P 將他添加到列表中。 PN+1現在是列表中的最后一個並等待信號(這按預期工作)。
  • 刪除第一個並重建n-1 個進程的列表是我卡住的地方。 基本上我記住n ,我向列表中的每個進程P發送一個SIGINT信號並將它們從列表中刪除。 到目前為止一切正常。 我有一個空列表,我必須用n-1 個進程重新填充。 所以我重新初始化列表(添加一個進程P1與在整個程序開始時添加的方式相同),然后添加剩余的n-2

output 的示例是:

p
Process list: 30594
(+) Process 30611 [id:pkDHTxmM] appended to the list.
(+) Process 30612 [id:R18N2l9k] appended to the list.      // Pressed four times
(+) Process 30615 [id:88EmLgN7] appended to the list.      // button 2
(+) Process 30616 [id:cCCTt9rW] appended to the list.
p
Process list: 30594 -> 30611 -> 30612 -> 30615 -> 30616
(-) First process (30594) removed.                         // Pressed once first button
p
Process list: 30619 -> 7 -> 6370080 -> 6370120

任務管理器現在只顯示主進程P和四個S進程。 經過大量檢查后,我發現 M_process.c 中的initialize_list() function中的分叉不起作用。 主進程從fork()接收到一個新的 pid,實際上該 pid 已添加到列表中(output 示例中的 30619),但實際上不存在具有該 pid 的現有進程。 它甚至不會被創建並立即退出,因為我試圖在pid == 0分支中放置一個打印語句並且沒有任何反應。 當列表中只有一個元素P1時,它確實按預期工作(另一件事我無法解釋自己)。

我真的不明白為什么fork()調用會返回一個 pid 給主進程P ,但實際上不會創建一個具有該 pid 的子進程,這似乎是讓我無法繼續進行該項目的問題。

(我意識到這一切都很混亂,可能不太清楚,但我發現很難總結我需要完成的工作和我目前的情況。此外,我意識到我發布這個問題的方式不允許你測試它,但由於還要處理硬件部分,我認為它會變得更加復雜。)

initialize_list中的fork確實創建了一個新進程,但在安裝信號處理程序之前,它會立即被add_process中的kill ,發送SIGUSR1

您可以在fork之前阻止信號,然后在安裝信號處理程序和在父級中取消阻止它,或者在調用fork之前安裝信號處理程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM