上期我们已经学习了进程的基础的内容,已经对进程的基本概念有了了解,知道了进程的组成, 本期我们将以操作为主进一步探讨进程的相关概念。
目录
查看进程
创建进程
查看进程
查看进程主要有两种方式。
ps ajx指令
在当前目录下有名为test的可执行文件。
可执行文件test被加载到内存之后运行便成为了进程,所以也有其独有的进程id编号。我们可以通过ps ajx指令查看名为test的进程。
ls /proc指令
可以理解为所有进程都是一个目录,目录的名称就是每个进程的pid。
ctrl+c可以终止当前进程。
创建进程
进程的创建,为操作系统自动创建和程序员自己通过对应的函数进行创建。操作系统自动创建即代码编译之后形成可执行程序,然后直接运行程序之后变成进程。不过这不是我们本期讨论的重点,本期的重点是我们如何使用函数自己创建进程。
fork函数:使用fork函数创建子进程。
#include<iostream> #include<unistd.h> using namespace std; int main() { //创建子进程 int id=fork(); cout<<"hello world"<<endl; return 0; }
分析上述代码,我们预期的结果应该打印一行“hello world”。运行结果如下:
通过运行接过我们可以看到,竟然打印了两行“hello world ”,这究竟是为什么呢?这就是fork()函数的功劳,fork()函数在当前进程下,创建了子进程。子进程继承了父进程的task_struct(进程控制块),因为进程控制块里面有内存指针,内存指针指向了父进程的代码和数据,子进程继承父进程的内存指针之后,也可以去访问父进程的代码和数据,所以父进程的代码和数据对于子进程而言是共享的,但是对于数据而言,当父子进程其中一个进程要进行修改时,要进行写时拷贝的操作。所以说了这么多,其实就是当前进程创建了子进程之后,子进程也执行了创建函数fork()函数之后的代码。所以才会打印两份“hello world”。
fork函数返回值:创建子进程之后,对子进程返回0,对父进程返回子进程的pid,创建进程失败返回值小于0。
#include<iostream>
#include<unistd.h>
using namespace std;
int main()
{
//创建子进程int id=fork();if(id ==0){//子进程cout<< "I am child "<<getpid()<<endl;}else{//父进程cout<<id<<endl;cout<<"I am parent "<<getpid()<<endl;}return 0;
}
代码运行结果如下:
可见,先运行了父进程,然后运行了子进程。那么问题来了,整个代码执行的过程是怎么样的呢?在fork函数创建完子进程之后,父进程和子进程到底谁先执行呢?
1.在fork函数创建完进程之后,会返回函数的返回值,但是返回函数返回值之前,由于子进程已经创建,此时进程控制块中的上下文数据发挥了作用,即父进程执行完了fork函数,所以子进程要执行也得从fork函数执行完之后的下一句代码开始执行。
2.父子进程没有先后的执行顺序,主要看操作系统中调度器调度的策略,父子进程没有绝对的先后执行顺序。
进程的基本概念至此已经全部结束,后期我们将进一步探讨进程相关的操作。
本期内容到此结束^_^