- 主函数(main函数)的参数
int main(int argc, char *argv[],char *envp[]);
- argv :(char*)[] 传递main方法的参数列表
- argc :int --->传递给main方法的参数列表中的参数个数
- envp :(char*)[]传递环境变量列表
注:只要用户执行程序,main方法默认至少接收一个参数,此参数就是执行程序的命令
main方法传参:
2、输出缓冲区
不能以输出的顺序来决定程序运行的顺序
执行结果:先睡眠5秒,打印hello world
printf ---》将hello写入输出缓冲区
再执行sleep
printf ---》将world\n写入输出缓冲区)
输出缓冲区中的内容刷新到界面上的条件:
- “\n”
- 手动刷新 fflush(stdout);
- 缓冲区满
- 进程结束
_exit(不管缓冲区是什么状态是否有数据,直接结束进程,不会刷新缓冲
exit(如果缓冲区有数据,先把缓冲区里的数据刷出来,然后在结束进程)
3、进程创建
用户--》 启动进程 --》 路径+程序名
程序 --》 通过一个进程创建另一个进程
fork 函数原型: pid_t fork(void);
函数返回类型 pid_t 实质是 int 类型,
fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。fork 函数调用一次,返回两次,在父进程中返回子进程的 pid,在子进程中返回0,失败返回-1。fork 函数在生成子进程时,用到了写时拷贝技术:不执行一个父进程数据段、栈和堆的完全复制,这些区域由父、子进程共享,而内核将他们的访问权限改为只读的。如果父、子进程中任何一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本,并且是以虚拟存储器系统中的“一页”为单位复制。
fork()方法:
- pid_t fork(void);-
------》 创建一个进程(pid_t实际是int类型的)
fork函数会生成一个进程,调用fork函数的进程为父进程,新生成的进程为子进程,
在父进程中返回子进程的pid,在子进程中返回0,失败返回-1。
- pid_t getpid();
-------》 获取当前进程的PID值
(在进程上通过PID来标识一个进程)
- pid_t getppid();
-------》 返回当前进程的父进程PID
父进程中返回子进程的pid来找子进程
每个进程的PCB中都保存了其父进程是谁
fork()方法调用后,父子进程都从fork调用之后的指令开始执行
pid_t pid = fork(); 改成汇编
------》 call fork //执行过了
mov pid exa //开始执行
父进程执行else打印--hello,子进程执行if打印--world
想让父进程执行的放入else,想要子进程执行的放入if,若不在if,else中的但在fork中的,两个进程都可执行
(父进程创建的子进程有多个未知,但子进程的父进程只有一个,在每一个进程里的PCB结构里,专门有一个成员,用来记录其进程的父进程是谁但是没有任何一个成员去记录当前进程的子进程是谁。fork后,父子进程都成为了两个独立的进程,只有一个父子关系,它的执行、调用、调度都无关系,如果需要控制,父进程创建时记录子进程的pid)
fork之后,父子进程是并发执行的
4、实现
子进程的修改对父进程没有影响
操作系统为每一个进程维护一个页表