进程和线程(1)

1、进程的概念

  程序是存放在存储介质上的一个可执行文件;
  当一个程序运行时被称之为进程;进程是一个程序的一次执行过程;
  程序是静态的,他是一些保存在磁盘上的指令的有续集合。
  进程是一个动态的概念,他是程序执行的过程,包括创建、调度、和消亡。
  进程是程序执行和资源管理的最小单位。

2、进程的内存管理

  当创建或者运行一个新的进程时,操作系统都会在内存中给当前进程分配空间,但是为了更好的解决进程之间的交互问题,系统给每一个进程分配的内存空间称之为虚拟内存,在32位操作系统中,每一个进程所占的虚拟内存是4G,4G的虚拟内存又分为1G的内核空间和3G的用户空间,内核空间时当前主机中所有进程共有的,用户空间是当前进程私有的。
在这里插入图片描述
虚拟内存与物理内存的关系是互相映射的,有时间单独总结一期。
在这里插入图片描述

3、进程号

  每一个进程都设有一个进程号来标识的,器类型为pid_t,进程号的范围:0~32767。
  进程号总是唯一的,但是金超可以重用。当一个进程终止后,其进程号就可以在此使用了。
  进程号是由操作系统自动分配的
  特殊的进程号:
  0:内核进程,是当前系统开启是最先创建的进程
  1:init进程,是所有的进程的祖先

4、Linux中进程的类型

交互进程:
  改类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。执行程序后,命令行界面ctrl +z 将进程软中断,bg将进程运行到后端,在此输入fg将进程在此调到前端。
批处理进程:
  该类进程不属于某个终端,他会提交到一个队列中一遍顺序执行。
守护进程:
  该类进程在后台运行,他一般在linux启动时开始执行,系统关闭时才结束。
特殊的进程:
  孤儿进程、守护进程、僵尸进程;
  父进程退出,子进程没有退出,此时子进程成为孤儿进程。守护进程是特使的孤儿进程。当父进程创建子进程后,子进程退出,但子进程的资源没有释放,此时的子进程成为僵尸进程,僵尸进程会消耗资源。
相关命令:
  查看进程使用ps命令;ps aux或ps -ef
  杀死进程kill 进程号;kill all 进程名;

4、进程状态及转换

进程整个声明周期可以简单划分为三种状态:
就绪态:
  进程已经具备执行一切条件,正在等待分配cpu的处理时间。
执行态:
  该进程正在占用CPU运行。
等待态:
  进程因不具备某些执行条件而暂时无法继续执行的状态。
在这里插入图片描述
进程的调度:时间片轮转,上下文切换。

5、创建进程

1、fork()

#include <unistd.h>
pid_t fork(void);
功能:在已有的进程基础上有创建一个子进程
参数:
    无
返回值:
    成功:
        >0  子进程的进程号,标识父进程的代码区
        0   子进程的代码区
    失败:
        -1 返回给父进程,子进程不会创建

例如:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    //使用fork创建一个子进程
    //只要执行fork,就会创建子进程
    //通过fork的返回值来决定父进程如何运行,子进程如何运行
    //进程之间是来回切换执行的,父子进程没有先后顺序可言
    pid_t pid;
    
    if((pid = fork()) < 0)
    {
        perror("fail to fork");
        return -1;
    }
    else if(pid > 0) //父进程的代码区
    {
        printf("This is parent process\n");
        sleep(1);
        printf("***************\n");
    }
    else //子进程的代码区
    {
        printf("This is child process\n");
        sleep(1);
        printf("---------------\n");
    }
    
    //父子进程的代码区不仅限于fork的返回值对应的if、else语句
    //要分析父子进程什么时候结束才不会再运行
    printf("nihao chengdu\n");

    return 0;
}

父子进程之间的关系

#include <stdio.h>
#include <unistd.h>

int a = 100;

int main(int argc, char const *argv[])
{
    static int b = 200;
    int c = 300;

    //当fork函数执行结束后,会创建一个子进程
    //子进程会复制父进程的所有的虚拟内存,此时子进程和父进程再没有任何联系
    //每一个进程拥有私有的用户空间,所以子进程创建后,不管父进程如何操作(对用户空间的操作)
    //都不会影响子进程
    
    //总结:父子进程公有的是fork之前的数据,fork之后
    //不管如何操作自己的用户空间,相互都没有影响
    pid_t pid;
    pid = fork();
    if(pid < 0)
    {
        perror("fail to fork");
        return -1;
    }
    else if(pid > 0) //父进程
    {
        printf("This is parent process\n");
        a++;
        b++;
        c++;
        printf("parent process: %p -- %p -- %p\n", &a, &b, &c);
        printf("parent process: %d, %d, %d\n", a, b, c);
    }
    else //子进程
    {
        printf("This is child process\n");
        printf("child process: %p -- %p -- %p\n", &a, &b, &c);
        printf("child process: %d, %d, %d\n", a, b, c);
    }

    while(1)
    ;

    return 0;
}

2、getpid()/getppid()

#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
功能:获取当前进程的进程号
参数:
    无
返回值:
    成功:当前进程的进程号

pid_t getppid(void);
功能:获取当前进程的父进程的进程号
参数:
    无
返回值:
    常规:当前进程的父进程的进程号

例如:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    pid_t pid;

    if((pid = fork()) < 0)
    {
        perror("fail to fork");
        return -1;
    }
    else if(pid > 0) //父进程
    {
        printf("This is parent process\n");
        printf("pid = %d\n", pid);
        printf("parent: pid = %d, ppid = %d\n", getpid(), getppid());
    }
    else //子进程
    {
        printf("This is child process\n");
        printf("child: pid = %d, ppid = %d\n", getpid(), getppid());
    }

    while(1)
    ;

    return 0;
}

3、exit()/_exit()

#include <unistd.h>
void _exit(int status);
功能:退出当前进程
参数:
    status:退出状态,由父进程通过wait函数接收这个状态
        一般失败退出设置为非0
        一般成功退出设置为0
返回值:
    无

#include <stdlib.h>
void exit(int status);
功能:退出当前进程
参数:
    status:退出状态,由父进程通过wait函数接收这个状态
        一般失败退出设置为非0
        一般成功退出设置为0
返回值:
    无

例如:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void myfun()
{
    printf("nihao chengdu");

    //return只能在主函数中用于退出进程,在子函数中只能退出函数
    //return ;

    //使用exit退出进程
    //exit函数可以刷新缓冲区,常用
    exit(0);
    
    //使用_exit退出进程
    //_exit函数不会刷新缓冲区
    //_exit(0);

    printf("nihao beijing\n");
}

int main(int argc, char const *argv[])
{
    printf("hello world\n");

    myfun();

    printf("hello kitty\n");
    
    return 0;
}

4、wait()/waitpid()

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
功能:阻塞等待子进程退出
参数:
    status:子进程退出时如果使用exit函数,
            那么子进程的退出状态会被当前参数接收到
            
            如果不想接收子进程的退出状态或者子进程没有调用exit
           则这个值设置为NULL
返回值:
    成功:退出的子进程的进程号
    失败:-1

pid_t waitpid(pid_t pid, int *status, int options);
功能:阻塞等待子进程退出
参数:
    pid:
        <-1 等待指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值
        -1  等待任一子进程,此时waitpid和wait作用一样
        0   等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会等待它
        >0  等待进程ID等于pid的子进程
    status:子进程退出时如果使用exit函数,
            那么子进程的退出状态会被当前参数接收到
            
            如果不想接收子进程的退出状态或者子进程没有调用exit
            则这个值设置为NULL
    options:选项
        0         阻塞        
        WNOHANG   非阻塞
返回值:
    成功:退出的子进程的进程号
    失败:-1
    
wait(NULL) <==> waitpid(-1, NULL, 0)   

例如:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char const *argv[])
{
    pid_t pid;

    if((pid = fork()) < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if(pid > 0) //父进程
    {
        printf("This is parent process\n");

        //wait:阻塞等待子进程退出,如果子进程不退出,他会一直阻塞下去
        int status;
        //wait(&status);
        waitpid(-1, &status, 0);
        printf("status = %#x\n", status);
        printf("hello world\n");
    }
    else //子进程
    {
        printf("This is child process\n");

        sleep(5);

        //exit(2);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/ZBraveHeart/article/details/123257253
今日推荐