操作系统之shell实现(上)
🌟 各位看官好,我是maomi_9526!
🌍 种一棵树最好是十年前,其次是现在!
🚀 今天来学习C语言的相关知识。
👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦
目录
1. 进程创建
1.1fork函数
编辑
1.2写时拷贝(Copy-on-write)
1.3 虚拟地址存储
2. 进程终止
2.1进程退出情况
2.2退出方式
2.3退出码
2.4exit函数VS_exit函数
2.4.1exit函数
2.4.2_exit函数
编辑 2.4.3eixt VS_exit编辑
3. 进程等待
3.1进程等待的必要性
3.2wait等待
3.3获取子进程status
4.总结
1. 进程创建
1.1fork函数
fork()
是 Linux 中非常重要的函数,用来从父进程创建一个子进程。父进程返回子进程的PID,子进程返回0。通过 fork()
创建的父子进程可以独立执行各自的代码。
头文件:#include<unistd.h>
返回值:成功父进程返回孩子pid,子进程返回0。失败返回-1。
函数:pid_t frok(void);
#include<stdio.h>
#include<unistd.h>int main()
{printf("Befor pid is %d\n",getpid());pid_t id=fork();if(id==-1){perror("fork()");exit(1);}printf("After:pid is %d,return id is %d \n",getpid(),id);
}
结果:
1.2写时拷贝(Copy-on-write)
fork()
使父子进程共享相同的内存内容,直到其中一个进程对内存进行修改,这时才会进行拷贝,避免不必要的资源浪费。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
int main()
{int a=0;printf("Befor pid is %d\n",getpid());pid_t id=fork();if(id==-1){perror("fork()");exit(1);}printf("After:pid is %d,return id is %d \n",getpid(),id); }
此时三个地址:a取地址一样
1.3 虚拟地址存储
尝试在子进程中修改a的地址后,查看a的地址。
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
int main()
{int a=0;printf("Befor pid is %d,path is %p\n",getpid(),&a);pid_t id=fork();if(id==-1){perror("fork()");exit(1);}if(id==0) {int a=15;printf("After:pid is %d,return id is %d ,path is %p\n",getpid(),id,&a); }elseprintf("After:pid is %d,return id is %d ,path is %p\n",getpid(),id,&a);}
三个地址仍然相同?这是为什么呢?
两个虚拟地址相同的原因在于它们位于不同的虚拟页面上,但在各自的虚拟页面内,偏移量相同。因此,尽管它们属于不同的虚拟内存块,最终的虚拟地址值却相同。
2. 进程终止
2.1进程退出情况
- 代码运行完毕,结果正常
- 代码运行完毕,结果不正常
- 进程异常终止
2.2退出方式
如果系统正常终止可以通过$?来查看进程退出码
- 从main函数返回
- 调用exit
- 调用_exit
2.3退出码
每个进程都有一个退出码,0
表示正常退出,非 0
表示出错。
2.4exit函数VS_exit函数
2.4.1exit函数
#include <unistd.h>
#include<stdlib.h>
void exit(int status);
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{printf("exit");exit(1);}
2.4.2_exit函数
#include <unistd.h>
#include<stdlib.h>
void _exit(int status);
#include<stdio.h>
#include<unistd.h>
int main()
{printf("_exit");_exit(1);}
2.4.3eixt VS_exit
3. 进程等待
3.1进程等待的必要性
- 之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存
- 泄漏。
- 另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
- 最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对,或者是否正常退出。
- 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
3.2wait等待
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
pid_t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:输出型参数
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:默认为0,表示阻塞等待WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等
待。若正常结束,则返回该子进程的ID。
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
3.3获取子进程status
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{int id=0;int cur=5;id=fork();if(id==-1){perror("fork");}if(id==0){while(cur--){printf("My pid is %d,My ppid is %d\n",getpid(),getppid());}sleep(1);exit(1);}int status=0;int idd=waitpid(id,&status,0);printf("idd is %d,status is %d\n",idd,status);}
3.3.1退出码
为什么退出码是256而不是1?
printf("idd is %d,status is %d\n",idd,(status>>8));
3.3.2终止信号
3.3.3 WIFEXITED
是一个宏值,与&0x7F取得的效果相仿
程序正常运行为:真
程序异常退出为:假
3.3.4WEXITSTATUS
是一个宏值,与(>>8)&&0xFF取得的效果类似
3.4非阻塞查询(wnohang)和阻塞查询(0)
4.总结
1.Linux下的错误码及描述
0->Success
1->Operation not permitted
2->No such file or directory
3->No such process
4->Interrupted system call
5->Input/output error
6->No such device or address
7->Argument list too long
8->Exec format error
9->Bad file descriptor
10->No child processes
11->Resource temporarily unavailable
12->Cannot allocate memory
13->Permission denied
14->Bad address
15->Block device required
16->Device or resource busy
17->File exists
18->Invalid cross-device link
19->No such device
20->Not a directory
21->Is a directory
22->Invalid argument
23->Too many open files in system
24->Too many open files
25->Inappropriate ioctl for device
26->Text file busy
27->File too large
28->No space left on device
29->Illegal seek
30->Read-only file system
31->Too many links
32->Broken pipe
33->Numerical argument out of domain
34->Numerical result out of range
35->Resource deadlock avoided
36->File name too long
37->No locks available
38->Function not implemented
39->Directory not empty
40->Too many levels of symbolic links
41->Unknown error 41
42->No message of desired type
43->Identifier removed
44->Channel number out of range
45->Level 2 not synchronized
46->Level 3 halted
47->Level 3 reset
48->Link number out of range
49->Protocol driver not attached
50->No CSI structure available
51->Level 2 halted
52->Invalid exchange
53->Invalid request descriptor
54->Exchange full
55->No anode
56->Invalid request code
57->Invalid slot
58->Unknown error 58
59->Bad font file format
60->Device not a stream
61->No data available
62->Timer expired
63->Out of streams resources
64->Machine is not on the network
65->Package not installed
66->Object is remote
67->Link has been severed
68->Advertise error
69->Srmount error
70->Communication error on send
71->Protocol error
72->Multihop attempted
73->RFS specific error
74->Bad message
75->Value too large for defined data type
76->Name not unique on network
77->File descriptor in bad state
78->Remote address changed
79->Can not access a needed shared library
80->Accessing a corrupted shared library
81->.lib section in a.out corrupted
82->Attempting to link in too many shared libraries
83->Cannot exec a shared library directly
84->Invalid or incomplete multibyte or wide character
85->Interrupted system call should be restarted
86->Streams pipe error
87->Too many users
88->Socket operation on non-socket
89->Destination address required
90->Message too long
91->Protocol wrong type for socket
92->Protocol not available
93->Protocol not supported
94->Socket type not supported
95->Operation not supported
96->Protocol family not supported
97->Address family not supported by protocol
98->Address already in use
99->Cannot assign requested address
100->Network is down
101->Network is unreachable
102->Network dropped connection on reset
103->Software caused connection abort
104->Connection reset by peer
105->No buffer space available
106->Transport endpoint is already connected
107->Transport endpoint is not connected
108->Cannot send after transport endpoint shutdown
109->Too many references: cannot splice
110->Connection timed out
111->Connection refused
112->Host is down
113->No route to host
114->Operation already in progress
115->Operation now in progress
116->Stale file handle
117->Structure needs cleaning
118->Not a XENIX named type file
119->No XENIX semaphores available
120->Is a named type file
121->Remote I/O error
122->Disk quota exceeded
123->No medium found
124->Wrong medium type
125->Operation canceled
126->Required key not available
127->Key has expired
128->Key has been revoked
129->Key was rejected by service
130->Owner died
131->State not recoverable
132->Operation not possible due to RF-kill
133->Memory page has hardware error