LINUX多进程

目录

一 进程基本概念

二 进程状态转换

三 进程创建

 四 父子进程虚拟地址空间

五 exec函数族

六 进程控制


一 进程基本概念

程序包含:

        二进制格式标识(包含描述可执行文件格式的元信息(大小等))

        机器语言指令:对程序算法进行编码

        程序入口地址

        数据(程序的变量初始值,字面量值等)

        符号表和重定位表:描述函数,变量的位置及名称,包含调试运行时的符号解析。

        共享库和动态链接信息:他们的路径名

用来指导如何创建进程。 只占据磁盘,不占据cpu,内存等资源。

进程: 占据磁盘,占据cpu,内存等资源。

        是正在运行的程序的实例,操作系统执行的基本单元。实质上是内核定义的抽象实体,并为该实体分配的用于执行程序的各系统资源。

        从内核看,由用户内存空间和内存数据结构组成。内核数据结构用于维护进程状态信息,记录进程标识号,虚拟内存表,进程资源使用等信息。

时间片: 处理器分配给每个正在运行的进程的微观上一段CPU时间。通常很短(Linux:5-800ms)。 第一次给每个进程分配相同时间,轮番执行后,所有时间片耗尽,内核为其重新计算并分配。

并行:多个处理器上同时多条指令运行

并发:一个处理器上多条指令快速切换运行,导致看上去在同时运行。

PCB:进程控制块,由内核为每个进程分配,维护进程相关信息。(本质是一个结构体)

        进程id: pid_t类型   0-32767 唯一但可以重用            进程状态:就绪,运行,挂起,停止等。

        进程切换时需要保存,恢复的CPU寄存器                虚拟地址空间信息

        控制终端信息                                                            当前工作目录

        文件描述符表等

除了init进程,任何进程都由另一个进程创建,对应进程号PPID 。

进程组是一个/多个进程的集合,可以接受同一终端的各种信号,有一个PGID。

pid_t getpid(void)//获取进程号

pid_t getppid(void)//获取父进程号

pid_t getpgid(pid_t pid)//获取pid所属组进程号

二 进程状态转换

进程状态:(新建),就绪,运行,阻塞,(终止)岁进程执行和外界条件变化而转换。

就绪态:进程具备运行条件,等待系统分配处理器才可以运行。处于就绪队列中

运行态:  拥有CPU正在运行

阻塞态:(wait/sleep态) 不具备运行条件,正等待其他事件完成。

新建态:进程刚被创建,还未进入就绪队列。

终止态:完成任务结束或异常终止或被操作系统,有终止权的进程所终止。终止后保留在操作系统里等待善后,当其他进程完成对该进程的信息抽取后,操作系统删除该进程 。

 查看命令

ps aux/ajx
u:进程详细信息
x:没有控制终端的信息
j:与作业相关的信息

 top可以实时显示进程动态 

        显示后按 M 可以按内存大小排序,   U 用户名可以显示所属该用户的进程

kill 杀死进程

         kill 进程号可以杀死别的进程   kill -9(-SIGKILL) 进程号,强制杀死,可以用来杀死自己进程。(kill -9是发了一个信号,该信号能杀死进程)

ps:运行进程时 加上& 如  ./a.out &可以让他在后台运行,不阻塞终端,只是输出到终端

进程创建

int main()
{
    //成功则在父进程中返回创建的子进程的pid_t. 在子进程中返回0.父进程返回-1则创建失败
    //失败:1 当前进程数达到系统规定上线,errno:EAGAIN  2 系统内存不足,errno:ENOMEM
    pid_t pid1 = fork();
	cout<<pid1<<endl;
    if(pid1>0)
    {//父进程
        printf("I am father pid %d %d\n",getpid(),getppid());
    }
    else if(pid1==0)
    //子进程
        printf("I am child pid%d %d\n",getpid(),getppid());

    for(int i=0;i<5;i++)
    {//父子进程交替执行
        cout<<i<<" "<<getpid()<<endl;
        sleep(1);
    }
    return 0;
}

 父子进程虚拟地址空间

        fork()时通过写时复制实现(可以推迟甚至避免拷贝)(针对物理空间)

        刚开始内核让父子进程只读地共享同一个地址空间(用户区数据,fd表),直到需要写入时才会复制地址空间,让他们各自拥有自己的地址空间。子进程会拷贝父进程的用户区,内核区也会拷贝,但是pid不同。

        父子进程相同的fd指向相同的文件,引用计数增加,

exec函数族

(execute) 作用:根据指定文件名找到可执行文件,即在调用程序内部执行一个可执行文件

执行成功后不会返回,原程序后面内容不再执行, 失败返回-1,从原程序调用点接着往下。

int execl(const char* path,const char*arg,...);
        //path:需要执行的文件路径 推荐绝对路径
        //args: 执行文件的名称,函数需要的参数列表...需要以null结束(哨兵)

int main()
{
    pid_t pid=fork();
    if(pid>0)
    {
        cout<<"i am parent process, pid: "<<getpid()<<endl;
    }
    else if(pid==0)
    {
        execl("test","test",nullptr);
        //execl("/bin/ps","ps","aux",nullptr);   //which ps可以查找其所在位置
        cout<<"i am child\n";
    }
    cout<<"alllll, "<<getpid()<<endl;
    return 0;
}


test.cpp
int main()
{
    cout<<"i am test()\n";
	
    return 0;
}

 输出结果

 int execlp(const char*file,const char* args,...)

        //没指定路径时 从环境变量里查找

  int execv(const char*file,char* const argvs[],...) //参数用数组存储

进程控制

退出进程 exit(int status)(stdlib.h)   _exit(int status)(unistd.h)

        exit会刷新IO缓冲,输出缓冲区里的内容,_exit()会直接退出,缓冲区里的内容被丢弃。

孤儿进程 :父进程结束,子进程还在运行。被init进程接管回收资源。所以孤儿进程不会有危害。

僵尸进程:进程终止时,会释放用户区数据,但是内核区PCB需要父进程释放,如果父进程不调用wait() /waitpid(),该进程号就会一直占用,PCB一直存在内核,变为僵尸进程。 僵尸进程不能被kill -9杀死。

        解决方案:

                1)此时可以杀死父进程,使init接管该僵尸进程,回收资源。

                2) wait()/waitpid()得到子进程退出状态同时清除该进程的相关资源,但一次只能处理一个进程。

 pid_t wait(int *wstatus)

                        //阻塞  直到一个子进程退出,或者收到一个不能被忽略的信号才被唤醒,往下执行

                        *wstatus: 进程退出时的状态信息,传入的是一个int类型的地址,传出参数。

                        成功返回被回收的进程id,失败:-1(所有子进程都结束)         

int main()
{
    pid_t pid;
    for(int i=0;i<5;i++)
    {
        pid=fork();
        if(pid==0)
            break;//防止产生孙子进程
    }
    
    if(pid>0)
    {
        while(1)
        {
            cout<<"parent: "<<getpid()<<endl;
            cout<<"destroy: "<<wait(nullptr)<<endl;
            sleep(1);
        }
    }
    else if(pid==0)
    {
        while(1)
        {
             cout<<"child: "<<getpid()<<endl;
             sleep(1);
        }      
    }
    return 0;
}

 可以看到wait被阻塞。 

 退出信息相关宏

int res;
wait(&res);
if(WIFEXITED(res))
    cout<<WEXISTSTATUS(res)<<endl;
if(WIFSIGNALED(res)
    cout<<WTERMSIG(res)<<endl;

 pid_t wait_pid(pid_t pid,int * wstatus,int options) 可以设置不阻塞与指定等待哪个子进程。

        //pid>0 回收某个子进程的pid   =0: 回收当前进程组的所有子进程   =-1:回收所有子进程,相当wait().<-1: 回收某个进程组的组id的绝对值。

        //options  0:阻塞 WNOHANG 非阻塞

        //>0 返回子进程id   =0  表示还有子进程没有退出  -1  都退出了

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值