用C语言写一个自己的shell-Part Ⅰ

文章介绍了UnixShell如何工作,强调了不能在主进程中直接执行用户命令的原因,以及为何使用fork系统调用来创建子进程实现隔离和容错。接着,讨论了如何使用sleep系统调用阻塞进程。此外,文章详细解释了僵尸进程的概念,指出过多的僵尸进程会耗尽进程表资源,并提供了使用wait和waitpid系统调用来防止僵尸进程的方法。
摘要由CSDN通过智能技术生成

https://indradhanush.github.io/blog/writing-a-unix-shell-part-2/

https://www.geeksforgeeks.org/zombie-processes-prevention/

https://www.geeksforgeeks.org/exit-status-child-process-linux/

https://www.cnblogs.com/wuyuegb2312/p/3399566.html

http://www.ppmy.cn/news/11615.html

Part Ⅰ--child process


How does a shell work?


A shell parses commands entered by the user and executes this.To be able to do this,the workflow of the shell will look like this:

  1. startup the shell

  1. wait for user input

  1. parse user input

  1. execute the command and return the result

  1. go back to 2.

However,we cannot execute the command the command in the main thread itself,because of the following reasons:

  1. An error caused by a command may cause the entire shell to stop working.

  1. Independent commands should have their own process blocks. This is known as isolation and falls under fault tolerance.

A fault-tolerant design enables a system to continue its intended operation, possibly at a reduced level, rather than failing completely, when some part of the system fails.

To be able to avoid this, we use the system call fork.

to learn fork system call

Significantly,parent process and child process are running the same program, but it does not mean they are identical. OS allocate different data and states for these two processes, and the control flow of these processes can be different.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
​
intmain() {
    pid_t child_pid=fork();
​
    //Zero: Returned to the newly created child process.
    if(child_pid==0) {
        printf("### Child ###\nCurrent PID: %d and Child PID: %d\n",getpid(),child_pid);
    } else {//Positive value: Returned to parent or caller. The value contains process ID of newly created child process.
        printf("### Parent ###\nCurrent PID: %d and Child PID: %d\n",getpid(),child_pid);
    }
    
    return 0;
}
### Child ###
Current PID: 14477 and Child PID: 0
### Parent ###
Current PID: 14468 and Child PID: 14477
or
### Parent ###
Current PID: 14468 and Child PID: 14477
### Child ###
Current PID: 14477 and Child PID: 0

To block process


We can use sleep system call to block child process or parent process.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
​
int main() {
    pid_t child_pid=fork();
​
    //Zero: Returned to the newly created child process.
    if(child_pid==0) {
        printf("### Child ###\nCurrent PID: %d and Child PID: %d\n",getpid(),child_pid);
    } else {//Positive value: Returned to parent or caller. The value contains process ID of newly created child process.
        sleep(1);//sleep for one second
        printf("### Parent ###\nCurrent PID: %d and Child PID: %d\n",getpid(),child_pid);
    }
    
    return 0;
}

You will see

### Child ###
Current PID: 14600 and Child PID: 0
and after a span of one second
### Parent ###
Current PID: 14591 and Child PID: 14600

Similarly,if you add the sleep(1) call to the child segment of our code instead,you will see parent process be executed immediately.But you will notice that the parent process has terminated.Then the child one is executed.

Zombie Processes and their Prevention


Zombie Process:

https://www.geeksforgeeks.org/zombie-processes-prevention/

When a process is created in UNIX using fork() system call, the parent process is cloned. If the parent process calls wait() system call, then the execution of the parent is suspended until the child is terminated. At the termination of the child, a ‘SIGCHLD’ signal is generated by the kernel which is delivered to the parent. Parent, on receipt of ‘SIGCHLD’ reads the status of the child from the process table.

Even though the child is terminated, there is an entry in the process table corresponding to the child where the status is stored. When the parent collects the status, this entry is deleted (or we also say the parent reaped its child process) . Thus, all the traces of the child process are removed from the system. If the parent decides not to wait for the child’s termination and executes its subsequent task, then at the termination of the child, the exit status is not read. Hence, there remains an entry in the process table even after the termination of the child. This state of the child process is known as the Zombie state.

Why should we prevent the creation of the Zombie process?

However,there is one process table per system. The size of the process table is finite. If too many zombie processes are generated, then the process table will be full. That is, the system will not be able to generate any new process, then the system will come to a standstill. Hence, we need to prevent the creation of zombie processes.

How to prevent it?

(*)wait() system call : It suspends execution of the calling process until one of its children terminates. Syntax of wait() system call:

pid_twait(int*status);

(*)The waitpid() system call : It suspends execution of the calling process until a child specified by pid argument has changed state. Syntax of waitpid() system call :

pid_twaitpid(pid_tpid, int*status, intoptions)

Note: By default, waitpid() waits only for terminated children, but this behavior is modifiable via the options argument such as WIFEXITED, WEXITSTATUS etc.If we don't want to use it,options=0

The value of pid can be :

  1. Less than -1 : Meaning wait for any child process whose process group ID is equal to the absolute value of pid.

  1. Equal to -1 : Meaning wait for any child process.

  1. Equal to 0 : Meaning wait for any child process whose process group ID is equal to that of the calling process.

  1. Greater than 0 : Meaning wait for the child whose process ID is equal to the value of pid.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
​
int main() {
    pid_t child_pid;
    pid_t wait_pid;
    int stat_loc;
​
    child_pid=fork();
​
    if(child_pid==0) {
        printf("### Child ###\nCurrent PID: %d and Child PID: %d\n",
               getpid(), child_pid);
    } else {
        waitpid(-1, &stat_loc, 0);
        printf("### Parent ###\nCurrent PID: %d and Child PID: %d\n",
               getpid(), child_pid);
    }
    return 0;
}

This is the basic frame of the shell.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fantasy`

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值