[英]Fork() does not create a child - C
我正在研究 Raspberry Pi 3B 上的操作系統項目。 我必須在 C 中實現一種流程管理器程序。 有一個主進程P必須處理進程P1 - P2 - P3 -...- PN的鏈表。 (這是一個過程鏈,意味着P1分叉P2 , P2分叉P3等等)。 該列表使用P1初始化, P的子元素作為其第一個元素。
在硬件層面上,分別有 4 個按鈕(1、2、3、4)和 4 個 LED,每對都由一個單獨的進程S管理。 這 4 個S進程也是主進程P的子進程,但不在鏈表中。 現在,每個按鈕都有在列表上執行的不同操作。
我已經正確實現了所有硬件部分, P和S進程通過管道進行通信,因此不在這個問題的 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;
}
實際上,列表中的進程除了等待信號之外什么都不做,然后它們要么退出要么分叉。 鏈表在另一個文件中實現,你可以假設它的基本和通用功能。
我的實現背后的想法基本上如下:
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.