C fork() 导致未指定的意外函数调用
C fork() causing unexpected function calls that aren't specified
我的第一个 Stack Overflow post,我是该网站的潜伏者,但我真的很想开始问自己的一些问题!
我正在使用 unistd.h 库了解 fork() 系统调用。我想测试我正在学习的东西。我按照一本教科书的例子,在 UNIX 中创建了一个简单的进程。我在 OSX 上这样做。我已经设置了一个创建 shell 的任务,我不想得到构建 shell 的完整答案,因此我问的是这个特定的系统调用,而不是整个程序.
代码 运行 本身完全没问题,并给出了预期的输出。
这是工作正常的代码:
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid;
pid = fork();
if(pid == 0){
printf("\nI'm the child\n\n");
}
else if(pid > 0){
printf("\nI'm the parent, child has pid: [%d]\n", pid);
}
else{
printf("ERROR");
}
return 0;
}
我的问题是,当我将它放入我的 shell 程序时,根据我在网上找到的内容,它导致了叉子炸弹。
创建这个进程的函数是用命令'test'调用的。当我 运行 该函数时,它提供与独立版本相同的输出,但是当我继续并退出时,它似乎在无限循环中再次调用该测试函数。然后我无法终止进程,因为我的计算机滞后了,显然是因为正在创建一堆进程,我必须重新启动计算机。我已经这样做了几次,但由于每次 运行 都需要重新启动,所以无法进行测试。
我有一个等待退出命令结束的 while 循环。代码应该是不言自明的,如下所示。我知道很多这是不好的做法,我只是想通过研究来测试这些概念,我相信我应该使用 wait() 系统调用,但我想了解为什么我的代码会导致这种情况发生。
完整节目:
main.c
#include "shell.h"
int main() {
clear();
printf("Jack's Shell\n");
shellLoop();
clear();
return 0;
}
shell.c
#include "shell.h"
void shellLoop(){
char command[MAX_STRING_LEN];
int exit = 1;
while (exit != 0){
printf("\njackdewinter$ ");
scanf("%s", &command);
exit = commandInterpreter(command);
}
}
int commandInterpreter(char * cmd){
char message[MAX_STRING_LEN];
if(strcmp(cmd, "exit") == 0){ /* Best way to test strings (Not just characters.) */
return 0;
}
else if(strcmp(cmd, "info") == 0){
info();
return 1;
}
else if(strcmp(cmd, "pwd") == 0){
shellMessage("Call PWD");
return 1;
}
else if(strcmp(cmd, "cd") == 0){
shellMessage("Call CD");
return 1;
}
else if(strcmp(cmd, "test") == 0){
shellMessage("Test Called.");
test();
return 1;
}
else if(strcmp(cmd, "help") == 0){
shellMessage("Call HELP");
return 1;
}
else{
shellMessage("Incorrect command entered.\nType help for assistance and a list of commands.");
return 1;
}
}
void info(){
shellMessage("This shell was created by Jack Dewinter");
}
void test(){
pid_t pid;
pid = fork();
if(pid == 0){
printf("Child\n");
}
else if(pid > 0){
printf("I'm the parent, child has pid %d\n", pid);
}
else{
printf("ERROR");
}
}
void shellMessage(char * message){ /* Using this for consistent shell messages. */
printf("\n%s\n", message);
}
shell.h
#define MAX_STRING_LEN 80
#define clear() printf("3[H3[J") /* Terminal escape codes for clearing the console */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
void shellLoop();
int commandInterpreter(char * cmd);
void info();
void test();
void shellMessage(char * message);
任何帮助将不胜感激,谢谢!
您正在创建的 child 将像他的父亲一样循环,并且您将让每个循环都有一个新进程。
fork : 创建确切的过程映像。
您可以做的是:
1-加入child(即父亲等待child完成)
2- 或者在 printf("Child\n") 之后添加一个 exit();这将结束 child,并保留父亲 运行。
当您使用 fork
创建新进程时,child 进程从分叉点继续。因此,您的 child 打印 "Child"、,但随后 return 来自 test
。所以它继续 运行 只有 parent 的代码应该是 运行ning.
您在较小的代码段中看不到这一点,因为您立即从 main
return 导致 child 进程退出。
您需要让 child 在完成它的部分后退出。此外,parent 应该 wait
用于 child,这样你就不会留下僵尸进程。
void test(){
pid_t pid;
pid = fork();
if(pid == 0){
printf("Child\n");
_exit(0); // exit child; use _exit instead of exit
//to prevent atexit handlers from being called
}
else if(pid > 0){
printf("I'm the parent, child has pid %d\n", pid);
// wait for child to finish
wait(NULL);
}
else{
printf("ERROR");
}
}
此外,在 shellLoop
中,将变量 exit
重命名为其他名称,因为您正在屏蔽库函数 exit
.
我的第一个 Stack Overflow post,我是该网站的潜伏者,但我真的很想开始问自己的一些问题!
我正在使用 unistd.h 库了解 fork() 系统调用。我想测试我正在学习的东西。我按照一本教科书的例子,在 UNIX 中创建了一个简单的进程。我在 OSX 上这样做。我已经设置了一个创建 shell 的任务,我不想得到构建 shell 的完整答案,因此我问的是这个特定的系统调用,而不是整个程序.
代码 运行 本身完全没问题,并给出了预期的输出。
这是工作正常的代码:
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid;
pid = fork();
if(pid == 0){
printf("\nI'm the child\n\n");
}
else if(pid > 0){
printf("\nI'm the parent, child has pid: [%d]\n", pid);
}
else{
printf("ERROR");
}
return 0;
}
我的问题是,当我将它放入我的 shell 程序时,根据我在网上找到的内容,它导致了叉子炸弹。
创建这个进程的函数是用命令'test'调用的。当我 运行 该函数时,它提供与独立版本相同的输出,但是当我继续并退出时,它似乎在无限循环中再次调用该测试函数。然后我无法终止进程,因为我的计算机滞后了,显然是因为正在创建一堆进程,我必须重新启动计算机。我已经这样做了几次,但由于每次 运行 都需要重新启动,所以无法进行测试。
我有一个等待退出命令结束的 while 循环。代码应该是不言自明的,如下所示。我知道很多这是不好的做法,我只是想通过研究来测试这些概念,我相信我应该使用 wait() 系统调用,但我想了解为什么我的代码会导致这种情况发生。
完整节目:
main.c
#include "shell.h"
int main() {
clear();
printf("Jack's Shell\n");
shellLoop();
clear();
return 0;
}
shell.c
#include "shell.h"
void shellLoop(){
char command[MAX_STRING_LEN];
int exit = 1;
while (exit != 0){
printf("\njackdewinter$ ");
scanf("%s", &command);
exit = commandInterpreter(command);
}
}
int commandInterpreter(char * cmd){
char message[MAX_STRING_LEN];
if(strcmp(cmd, "exit") == 0){ /* Best way to test strings (Not just characters.) */
return 0;
}
else if(strcmp(cmd, "info") == 0){
info();
return 1;
}
else if(strcmp(cmd, "pwd") == 0){
shellMessage("Call PWD");
return 1;
}
else if(strcmp(cmd, "cd") == 0){
shellMessage("Call CD");
return 1;
}
else if(strcmp(cmd, "test") == 0){
shellMessage("Test Called.");
test();
return 1;
}
else if(strcmp(cmd, "help") == 0){
shellMessage("Call HELP");
return 1;
}
else{
shellMessage("Incorrect command entered.\nType help for assistance and a list of commands.");
return 1;
}
}
void info(){
shellMessage("This shell was created by Jack Dewinter");
}
void test(){
pid_t pid;
pid = fork();
if(pid == 0){
printf("Child\n");
}
else if(pid > 0){
printf("I'm the parent, child has pid %d\n", pid);
}
else{
printf("ERROR");
}
}
void shellMessage(char * message){ /* Using this for consistent shell messages. */
printf("\n%s\n", message);
}
shell.h
#define MAX_STRING_LEN 80
#define clear() printf("3[H3[J") /* Terminal escape codes for clearing the console */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
void shellLoop();
int commandInterpreter(char * cmd);
void info();
void test();
void shellMessage(char * message);
任何帮助将不胜感激,谢谢!
您正在创建的 child 将像他的父亲一样循环,并且您将让每个循环都有一个新进程。 fork : 创建确切的过程映像。
您可以做的是: 1-加入child(即父亲等待child完成)
2- 或者在 printf("Child\n") 之后添加一个 exit();这将结束 child,并保留父亲 运行。
当您使用 fork
创建新进程时,child 进程从分叉点继续。因此,您的 child 打印 "Child"、,但随后 return 来自 test
。所以它继续 运行 只有 parent 的代码应该是 运行ning.
您在较小的代码段中看不到这一点,因为您立即从 main
return 导致 child 进程退出。
您需要让 child 在完成它的部分后退出。此外,parent 应该 wait
用于 child,这样你就不会留下僵尸进程。
void test(){
pid_t pid;
pid = fork();
if(pid == 0){
printf("Child\n");
_exit(0); // exit child; use _exit instead of exit
//to prevent atexit handlers from being called
}
else if(pid > 0){
printf("I'm the parent, child has pid %d\n", pid);
// wait for child to finish
wait(NULL);
}
else{
printf("ERROR");
}
}
此外,在 shellLoop
中,将变量 exit
重命名为其他名称,因为您正在屏蔽库函数 exit
.