天天看点

Linux进程控制(一)一 进程概述二 进程操作

博主初学Linux进程相关知识,暂时总结到这里,有什么错误问题,欢迎大家指正!

文章目录

  • 一 进程概述
    • Linux进程
  • 二 进程操作
    • 创建进程
      • 1.fork
      • 2.孤儿进程
      • 3.vfork函数

一 进程概述

进程这个东西呢,是操作系统的最核心概念,是操作系统资源管理的最小单位。

Linux操作系统借助于进程来管理计算机的软硬件资源,支持多任务的并行执行。

Linux进程

  1. 进程是一个动态的实体,是程序是一次执行过程,程序是保存在硬盘上的可执行代码,是静态的。
  2. 这里顺便提一下线程:线程就是在进程内部,比进程更小的独立运行的基本单位,并且不占资源,它可以创建和撤销一个进程或者线程。
  3. ps 或者pstree(将所有行程以树状图显示)可以查看系统的进程。
  4. 实际用户ID(uid):标识运行该进程的用户
  5. 有效用户(euid):标识以什么用户身份来运行进程。用户A运行了一个身份是root的程序,程序运行时有root权限,此时,实际用户ID是A,有效用户ID是root
  6. Linux进程分为:

代码段:存可执行代码

数据段:存全局变量,常量,静态变量

堆栈段:存函数,函数内部定义的局部变量

  1. LInux进程状态:

运行状态:R

中断状态:S

不可中断状态:D

僵死状态:Z

停止状态:T

  1. 后缀:

<:高优先级进程

N:低优先级进程

s:会话首进程

l:多线程进程

+:位于前台进程组

二 进程操作

LInux下对进程主要系统调用:

fork:创建新进程

exit:终止进程

exec:执行一个应用程序

wait:父进程挂起,等待子进程终止

getpid:获取当前进程ID

getppif:返回父进程ID

nice:改变进程优先级

创建进程

1.fork

当fork函数调用成功后,当前进程(父进程)会新创建一个子进程,所以它有两个返回值,

父进程调用fork时返回子进程ID,子进程调用后返回0,异常时返回-1.

我们用fork创建一个进程

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main(){
    pid_t pid;

    printf("Process Creation Study\n");
    pid = fork();
    switch(pid){
    case 0:		//此时为子进程
        printf("Chid running,CurPid is %d,ParentPid is %d\n",pid,getppid());
        break;
    case -1:	//出错
        perror("Wrong!\n");
        break;
    default:	//此时父进程
        printf("Parent is running,ChildPid is %d,ParenrPid is %d\n",pid,getpid());
        break;
    }
    exit(0);
}
           

细心的我们可以看到上面有getppid()和getpid()这两个长得极端相似的函数,事实上:

getpid返回当前进程标识,getppid返回父进程标识。

运行后:

Process Creation Study
Parent is running,ChildPid is 18867,ParenrPid is 18866
Chid running,CurPid is 0,ParentPid is 18866

           

其实由于内核所使用的调度算法不同,fork之后子进程和父进程的运行先后顺序是有可能不同的,大家如果有兴趣的话,可以试着多运行几次, 我们可能会有几种不同的输出结果。

事实上,在fork()后父进程和子进程就已经分离两者已经分成两部分,交替执行下面的程序代码

运行下面程序,我们更能直观的看出来父进程和子进程交替运行的情况

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main(){
    int pid;
    char * msg;
    int k;
    printf("Process Creation Study\n");
    pid = fork(); //父子进程分裂
    switch(pid){
    case 0:
        msg = "Child running";
        k = 3;
        break;
    case -1:
        perror("Wrong!\n");
        break;
    default:
        msg = "Parent is running";
        k = 5;
        break;
    }
    while(k>0){
        puts(msg);
        sleep(1);
        k--;
    }
    exit(0);
}
           

运行一下:

Process Creation Study
Parent is running
Child running
Parent is running
Child running
Parent is running
Child running
Parent is running
Parent is running
           

几点补充:

1.子进程会继承父进程包括用户,用户组ID,当前工作目录等,但它有自己唯一的进程ID

2.子进程共享父进程打开的文件描述符,但父进程的文件描述符改变不会影响子进程中的文件描述符

3.子进程不继承父进程设置的文件锁,警告

4.子进程未决信号集被清空

2.孤儿进程

如果父进程先于子进程结束,子进程就会成为孤儿进程(可真是形象呢)

成为孤儿进程后,正常来讲,此时的孤儿进程会由init进程收养,此时子进程ID为1。

其实不然!

详见我的另一篇博客:https://blog.csdn.net/weixin_43204126/article/details/96871493

3.vfork函数

1.fork下的子进程复制父进程的资源,自身独立,拥有良好并发性,但也因为其要复制过多资源,有时是并不需要的,这就徒增了系统调用开销

2.vfork下的子进程会直接和父进程共享地址空间,节省了不必要的开销

3.fork下的进程运行先后顺序取决于系统的调度算法,而vfork保证子进程先运行,如果在调用exit或exec使得父进程运行前,子进程要依赖父进程的某个行为,就会造成死锁

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int globvar = 0;
//int var = 0;

int main(){
    pid_t pid;
    int i;
    int var = 0;
    printf("fork is different with fork\n");
    //pid = fork();
    pid = vfork();
    switch(pid){
        case 0:
            i = 3;
            while(i--){
                printf("Child is running\n");
                globvar++;
                var++;
                sleep(1);
            }
                //exit(0);
            //}
            printf("child's globvar = %d,var = %d\n",globvar,var);
            exit(0);  //必须加这个,不然不正常退出子进程会导致父进程var乱码
            break;
        
        case -1:
            perror("something wrong!\n");
            exit(0);
        default:
            i = 5;
            while(i--){
                printf("Parent is running\n");
                globvar++;
                var++;
                sleep(1);
            }
            printf("Parent's globvar = %d,var = %d\n",globvar,var);
            exit(0);
    }
}


           

运行结果:

fork is different with fork
Child is running
Child is running
Child is running
child's globvar = 3,var = 3
Parent is running
Parent is running
Parent is running
Parent is running
Parent is running
Parent's globvar = 8,var = 8

           

当我们注释掉pid = vfork();,让//pid = fork();加入程序时,会有下面的运行结果:

fork is different with fork
Parent is running
Child is running
Child is running
Parent is running
Child is running
Parent is running
Parent is running
child's globvar = 3,var = 3
Parent is running
Parent's globvar = 5,var = 5
           

可以很直观的看出其区别

注:使用vfork要谨慎,最好不要让子进程修改父进程的全局和局部变量

继续阅读