在自实现的linux shell (c++)中防止僵尸进程
Preventing zombie processes in a self-implemented linux shell (C++)
我自己实现了一个linux shell。我刚刚完成,但我需要理清僵尸进程的问题。在这个程序中,通过在命令后添加"&",可以指定要运行的命令应该在后台运行。
例如,sleep 30 &将执行睡眠功能30秒,但立即允许用户输入另一个命令,而无需等待。
我的问题是,在我目前的实现中,后台进程启动了,但我不知道如何让它在完成执行时通知程序。
我需要知道它何时完成执行,因为我有一个名为"jobs"的内置函数。此函数将打印当前正在运行的程序列表。
理想情况下,如果我执行"sleep 30 &",然后在sleep结束之前立即运行"jobs",它应该显示如下内容:
[1] [PROCESS ID HERE] sleep 30 &
然而,如果30秒过去了,sleep已经完成执行,我希望它显示没有进程正在运行。现在,如果我运行"sleep 30 &",它显示为一个僵尸进程(在ps -e命令中)。我不想这样。我该如何解决这个问题?
下面是我的代码:#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <stack>
#include <vector>
#include <ctype.h>
#include <sstream>
using namespace std;
#define MAX_INPUT_STRING_SIZE 80
//This function executes the command that was entered
int executeCommand(char ** commandArguments, int mode, char **supplementalPointer);
//This function parses the command that was entered
int parseCommand(char* inputString, char * commandArguments[], char** supplementalPointer,
int *modePointer);
//A bit of string handling
void chop(char * sourcePointer);
//print the history of commands
void printHistory();
//print the list of background processes running
void printJobs();
//Return the nth command in the history of commands
string returnNth(int nth);
//Modes
#define NORMAL 00
#define OUTPUT_REDIRECT 11
#define INPUT_REDIRECT 22
#define PIPELINE 33
#define BACKGROUND 44
//This struct defines a job that is stored in the list of background processes
struct job
{
pid_t processID;
string command;
job(pid_t pid, string com)
{
processID = pid;
command = com;
}
};
//The history of commands entered
stack<string> commandHistory;
//A place to store commands that have been popped before that are added back in
stack<string> popHistory;
//The list of background processes currently running
vector<struct job> jobList;
int main(int argc, char *argv[])
{
int i, mode = NORMAL, numOfArguments;
size_t length = MAX_INPUT_STRING_SIZE;
char *cpt, *inputString, *commandArguments[MAX_INPUT_STRING_SIZE], *supplement = NULL;
//The string that holds the command that the user entered
inputString = (char*)malloc(sizeof(char)*MAX_INPUT_STRING_SIZE);
char currentDirectory[100];
//continue until "quit" has been entered
while(strcmp(inputString, "quitn") != 0)
{
mode = NORMAL;
//get and print the current working directory
getcwd(currentDirectory, 100);
cout<<"%"<<currentDirectory<<"% ";
//get the command from the user
getline(&inputString, &length, stdin);
executeFromHistory:
string inputStringS(inputString);
//push the command to the history stack
commandHistory.push(inputStringS);
//quit the program
if(inputStringS == "quitn")
{
continue;
}
//print the history
else if(inputStringS == "historyn")
{
printHistory();
continue;
}
//print the list of jobs
else if(inputStringS == "jobsn")
{
printJobs();
continue;
}
else if(inputStringS[0] == '!')
{
commandHistory.pop();
//execute the most recent command
if(inputStringS[1] == '!')
{
if(commandHistory.empty())
{
cout<<"No commands in history"<<endl;
}
else
{
inputStringS = commandHistory.top();
strcpy(inputString, inputStringS.c_str());
goto executeFromHistory;
}
}
//Execute the nth command in history (specified by user)
else if(isdigit(inputString[1]))
{
int nth;
inputStringS = inputStringS.substr(1);
istringstream iss(inputStringS);
iss >> nth;
if(commandHistory.size() < nth || nth < 1)
{
cout<<"No such command could be found"<<endl;
}
else
{
inputStringS = returnNth(nth);
strcpy(inputString, inputStringS.c_str());
goto executeFromHistory;
}
}
else
{
continue;
}
}
//Parse a command and execute
else
{
numOfArguments = parseCommand(inputString, commandArguments, &supplement, &mode);
//Change directory
if(strcmp(*commandArguments, "cd") == 0)
{
chdir(commandArguments[1]);
}
else
//Execute
{
int returnstatus = executeCommand(commandArguments, mode, &supplement);
if(returnstatus == -1)
{
cout<<"Execution failed"<<endl;
continue;
}
}
;
}
}
return 0;
}
int parseCommand(char * inputString, char *commandArguments[], char **supplementalPointer,
int *modePointer)
{
int numOfArguments = 0;
bool terminate = false;
char* sourcePointer = inputString;
//Continue until the character we are on is NULL and terminate flag has been tripped
while(*sourcePointer != ' ' && !terminate)
{
//New argument
*commandArguments = sourcePointer;
numOfArguments++;
while(*sourcePointer != ' ' && *sourcePointer != 't' && *sourcePointer != ' '
&& *sourcePointer != 'n' && !terminate)
{
//Handle various special characters
switch(*sourcePointer)
{
case '&':
*modePointer = BACKGROUND;
*commandArguments = ' ';
*sourcePointer++;
while(*sourcePointer == ' ' || *sourcePointer == 't')
{
sourcePointer++;
}
break;
case '>':
*modePointer = OUTPUT_REDIRECT;
*commandArguments = ' ';
*sourcePointer++;
while(*sourcePointer == ' ' || *sourcePointer == 't')
{
sourcePointer++;
}
*supplementalPointer = sourcePointer;
chop(*supplementalPointer);
terminate = true;
break;
case '<':
*modePointer = INPUT_REDIRECT;
*commandArguments = ' ';
sourcePointer++;
while(*sourcePointer == ' ' || *sourcePointer == 't')
{
sourcePointer++;
}
*supplementalPointer = sourcePointer;
chop(*supplementalPointer);
terminate = true;
break;
case '|':
*modePointer = PIPELINE;
*commandArguments = ' ';
sourcePointer++;
while(*sourcePointer == ' ' || *sourcePointer == 't')
{
sourcePointer++;
}
*supplementalPointer = sourcePointer;
terminate = true;
break;
}
sourcePointer++;
}
while((*sourcePointer == ' ' || *sourcePointer == 't' || *sourcePointer == 'n') &&
!terminate)
{
*sourcePointer = ' ';
sourcePointer++;
}
commandArguments++;
}
*commandArguments = ' ';
return numOfArguments;
}
void chop(char * sourcePointer)
{
while(*sourcePointer != ' ' && *sourcePointer != 't' && *sourcePointer != 'n')
{
sourcePointer++;
}
*sourcePointer = ' ';
}
int executeCommand(char** commandArguments, int mode, char ** supplementalPointer)
{
pid_t pid1;
pid_t pid2;
FILE *filePointer;
int mode2 = NORMAL;
int numOfArguments;
int status1;
int status2;
char * commandArguments2[MAX_INPUT_STRING_SIZE];
char * supplement2 = NULL;
int pipes[2];
//Pipeline
if(mode == PIPELINE)
{
if(pipe(pipes))
{
cout<<"Pipe failed"<<endl;
return -1;
}
parseCommand(*supplementalPointer, commandArguments2, &supplement2, &mode2);
}
pid1 = fork();
string str(*commandArguments);
//Push the command to the list of running processes
jobList.push_back(job(pid1, str));
if(pid1<0)
{
cout<<"Fork failed"<<endl;
return -1;
}
//Child process
else if(pid1 == 0)
{
switch(mode)
{
case BACKGROUND:
//Child process is a background process
setpgid(0, 0);
case OUTPUT_REDIRECT:
filePointer = fopen(*supplementalPointer, "w+");
dup2(fileno(filePointer), 1);
break;
case INPUT_REDIRECT:
filePointer= fopen(*supplementalPointer, "r");
dup2(fileno(filePointer), 0);
break;
case PIPELINE:
close(pipes[0]);
dup2(pipes[1], fileno(stdout));
close(pipes[1]);
break;
}
execvp(*commandArguments, commandArguments);
}
//Parent process
else
{
if(mode == BACKGROUND)
{
//Wait for child process to complete
;
}
else if(mode == PIPELINE)
{
waitpid(pid1, &status1, 0);
pid2 = fork();
string str2(*commandArguments2);
jobList.push_back(job(pid2, str2));
if(pid2 < 0)
{
cout<<"fork failed"<<endl;
return -1;
}
else if(pid2 == 0)
{
close(pipes[1]);
dup2(pipes[0], fileno(stdin));
close(pipes[0]);
execvp(*commandArguments2, commandArguments);
}
else
{
close(pipes[0]);
close(pipes[1]);
}
}
else
{
waitpid(pid1, &status1, 0);
}
}
return 1;
}
void printHistory()
{
int commandHistorySize = commandHistory.size();
int i;
string commandPop;
for(i = commandHistorySize; i > 0; i--)
{
commandPop = commandHistory.top();
cout<<i<<" "<<commandPop;
commandHistory.pop();
popHistory.push(commandPop);
}
for(i = 0; i < commandHistorySize; i++)
{
commandPop = popHistory.top();
popHistory.pop();
commandHistory.push(commandPop);
}
}
//Print list of running processes
void printJobs()
{
int i;
for(i = 0; i < jobList.size(); i++)
{
//If the process is no longer running, remove it from the list
if(kill(jobList[i].processID, 0 )!= 0)
{
jobList.erase(jobList.begin() + i);
}
}
for(i = 0; i < jobList.size(); i++)
{
cout<<"["<<i+1<<"] "<<jobList[i].processID<<" "<<jobList[i].command<<endl;
}
}
string returnNth(int nth)
{
int i;
int commandHistorySize = commandHistory.size();
string commandPop;
for(i = commandHistorySize; i > nth; i--)
{
commandPop = commandHistory.top();
commandHistory.pop();
popHistory.push(commandPop);
}
string returnvalue = commandHistory.top();
for(i = commandHistorySize; i > nth; i--)
{
commandPop = popHistory.top();
popHistory.pop();
commandHistory.push(commandPop);
}
return returnvalue;
}
您需要为SIGCHLD创建一个处理程序,该处理程序等待进程,然后使用signal(SIGCHLD,handler)启用处理程序。
相关文章:
- boost::进程间消息队列引发错误
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 是否可以通过C++扩展强制多个python进程共享同一内存
- IPC使用多个管道和分支进程来运行Python程序
- 异常属于C++中的线程还是进程
- WMI检测进程创建事件-c++
- c++多进程编写一个唯一的文件
- 如何在C++中将函数发送到另一个进程
- 在Qt Creator中,如何在连接到正在运行的进程后查看控制台输出
- 终止 QProcess 不会终止子进程
- 将返回值从 exe 传递到 bat,并将其传递给 C# 中的进程
- COM :是否可以查看是否存在对我的某个 COM 对象的进程外引用?我可以释放它吗?
- Windows 进程间同步类似事件?
- 同时分叉 100 个进程,有时有些进程会变成僵尸
- posix_spawn创建一个僵尸进程并返回成功
- Linux fork - execl,执行的进程变成僵尸
- 避免在C++中产生僵尸进程
- 从C++通过RPC启动新线程会导致进程陷入僵尸状态
- pthread_join失败是否会导致子进程成为僵尸
- 在自实现的linux shell (c++)中防止僵尸进程