进程线程DAY1-DAY2

进程线程的安排:

DAY1-DAY2:1、什么是进程?

                        2、进程间通信:传统的unix通信方式:1.无名管道;2.有名管道;3.信号

DAY3-DAY4:1、systemV提供的通信方式:1.共享内存;2.消息队列;3.信号量

                        2、线程

DAY1:

        1.什么是进程?

在Windows下,任务管理器中可以看到进程,图中,应用中的进程,我们随时可以关闭,但后台进程是开机则打开,关机则关闭。

 在Linux下,我们可以通过以下快捷键看相关进程。如:ps -aux、ps -ef、ps -aux、ps -axj、top、pstree等操作。(希望读者自己私下进程相关操作)

到底什么是进程呢?

程序的一次动态执行过程,包括创建、调度和消亡。

        1.1 进程和程序的区别

        程序(a.out)是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何任何执行的概念。

        进程(./a.out)是一个动态的概念,它是程序执行的过程,包括创建、调度和消亡。

        1.2 进程是程序执行和资源(内存)管理的最小单位

        

从图我们可以看出,进程与进程之间存在“竞争”关系。

 为什么说进程是资源管理的最小单位?

 因为每一个进程都会有0~4G的虚拟内存。

        1.3 如何区分不同的进程-->PID(子进程号)、PPID(父进程号)

        进程是由进程创建的,有父进程和子进程。

        2.进程的类型

        (1)交互进程

        交互进程是由shell控制和运行的。交互进程既可以在前台运行,又可以在后台运行。

        (2)批处理进程

        该类进程不属于某个终端。它被提交到一个队列中以便执行。

        (3)守护进程

        该类进程在后台运行没有亲缘关系,一般在Linux启动时开始执行,系统关闭时才结束。

        3、进程的状态

        (1)运行态:此时进程正在运行,或者准备运行。

        (2)等待态:此时进程在等待一个时间的发生或某种系统资源。

        (3)停止态:此时进程被中断。

        (4)死亡态:这是一个已终止的进程,但还在进程向量数组中占已有一个task_struct(PCB)结构。PCB结构(内核空间):包括进程控制块本身、打开的文件表象、当前目录、当前终端信息、线程基本信息、可访问的内存地址空间、PID、PPID、UID、EUID等,也就是说,内核通过PCB可以访问到进程的所有资源。

        4、进程的模式 

        进程的执行模式分为用户模式和内核模式。

        调度进程:nice-----按用户指定的优先级运行进程。

                          renice---改变正在运行进程的优先级。

                          优先级范围:-20~19,值越小,优先级越高。

        5、进程相关的系统调用

        5.1 创建进程

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

int main()
{
    //创建pid
    pid_t pid = fork();
    //判断pid的大小
    if(pid < 0)
    {
        perror("pid create error!\n");
        return -1;
    }
    if(pid > 0)
    {
        //父进程
    }
    else
    {
        //子进程
    }

    return 0;
}

         子进程会赋值父进程的几乎所有信息,在用户空间将赋值父进程用户空间的所有数据,复制父进程内核空间PCB中绝大部分信息

          注意:fork()函数是父进程调用的,在父进程返回值之前,子进程已经创建好了,父进程和子进程的返回值是不一样的。

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

int main()
{
    //创建pid
    pid_t pid = fork();
    //判断pid的大小
    if(pid < 0)
    {
        perror("pid create error!\n");
        return -1;
    }
    if(pid > 0)
    {
        //父进程
        while(1)
        {
            printf("I am your father!my son !\n");
            sleep(1);
        }
    }
    else
    {
        //子进程
        while(1)
        {
            printf("Yes,you are my father,but i want to be stronger!\n");
            sleep(1);
        }
    }

    return 0;
}

        在子进程创建成功之后,它会和父进程抢占资源,存在竞争关系。谁先调度,有调度算法去决定。

        5.2 getpid()和getppid()
                5.2.1 getpid()
//头文件
#include<sys/types.h>
#include<unistd.h>
//函数原型
pid_t getpid(void);
/*
    函数功能:获取进程的PID号
    返回值:返回调用进程的PID号
*/
pid_t getppid(void);
/*
    函数功能:获取进程的PPID号
    返回值:返回调用进程的PPID号
*/

          进程的后台顺序:./a.out(子进程)---->./a.out(父进程)---->bash---->terminal---->systemd---->init 。此过程可以用ps -axj去查看他们的子进程号和父进程号。     

        5.3 进程退出

        进程的退出有exit()/_exit()以及mian函数中的return

        

         注意:(1)exit会刷新缓冲区(2)_exit不会刷新缓冲区。

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

int main()
{
    //创建pid
    pid_t pid = fork();
    //判断pid的大小
    if(pid < 0)
    {
        perror("pid create error!\n");
        return -1;
    }
    if(pid > 0)
    {
        int i = 0;
        //父进程
        while(1)
        {
            if(i>4)
            {
                printf("hello process!\n");
                //exit(0);
                //_exit(1);
                return 0;
            }
            printf("I am your father!my son !\n");
            sleep(1);
            i++;
    }
    else
    {
        //子进程
        while(1)
        {
            printf("Yes,you are my father,but i want to be stronger!\n");
            sleep(1);
        }
    }

    return 0;
}
        5.4 wait和waitpid
                5.4.1 wait函数

                调用该函数使进程阻塞,直到任一个子进程结束或者是该进程接收到了一个信号为止。如果该进程没有子进程或者其子进程已经结束,wait函数会立即返回。

                   5.4.2 waitpid函数

5.4.2 waitpid函数

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
    //创建pid
    pid_t pid = fork();
    //判断pid的大小
    if(pid < 0)
    {
        perror("pid create error!\n");
        return -1;
    }
    if(pid > 0)
    {
        //wait(NULL);//阻塞函数,等待子进程退出
        wait(-1,NULL,0);//同wait
        //父进程
        while(1)
        {
          int ret = waitpid(-1,NULL,WNOHANG);
          printf("ret = %d\n",ret);
          printf("I am your father!my son !\n");
          sleep(1);
        }
    else
    {
        int i = 0;
        //子进程
        while(1)
        {
            if(i > 3)
            {
                exit(0);
            }            
            printf("Yes,you are my father,but i want to be stronger!\n");
            sleep(1);
            i++:
        }
    }

    return 0;
}

         获取子进程退出的状态:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
    //创建pid
    pid_t pid = fork();
    //判断pid的大小
    if(pid < 0)
    {
        perror("pid create error!\n");
        return -1;
    }
    if(pid > 0)
    {
        //wait(NULL);//阻塞函数,等待子进程退出
        wait(-1,NULL,0);//同wait
        //父进程
        while(1)
        {
          int ret = waitpid(-1,NULL,WNOHANG);
          if(WIFEXITED(status))
            {
                printf("该进程正常退出,退出状态为:%d\n",ret);
            }
          else if(WIFSIGNALED(status))
            {
                printf("退出信号为:%d\n",ret);
            }
          printf("I am your father!my son !\n");
          sleep(1);
        }
    else
    {
        int i = 0;
        //子进程
        while(1)
        {
            if(i > 3)
            {
                exit(0);
            }            
            printf("Yes,you are my father,but i want to be stronger!\n");
            sleep(1);
            i++:
        }
    }

    return 0;
}

        6、孤儿进程

        父进程先退出,子进程被systemd进程收养,变为后台进程。

        7、僵尸进程

        子进程先于父进程退出,父进程没有回收子进程的资源(task_struct),此时子进程就变为僵尸进程。

        注意:如果父进程一直不退出,子进程就一直保持僵死状态,直到父进程退出,task_struct就会被systemed回收。

        8、exec函数族

        不想让子进程执行父进程的代码段。

        

         l:表示列表

        v:向量(数组)

        p:系统会自动从环境变量“$PATH”所包含的路径中进行查找(不用添加路径)。

DAY2:

        1、守护进程

        1.1特点

        (1)在后台运行,与终端无关。

        (2)在系统不够启动时运行,系统关闭时停止运行。

         1.2进程与终端的关系

         区别:前台:进程与终端具有血缘关系;控制终端一样。

                    后台:与终端无关。

 想要实现守护进程:

        (1)不能与终端具有血缘关系。(2)守护进程没有控制终端(备注:?表示没有控制终端)

        1.3进程组

        进程组是一个或多个进程的集合。进程组由进程组ID来唯一识别。

        每一个进程组都有一个组长进程,进程组ID就是组长进程的进程号。

        1.4会话组

        会话组就是一个或者多个进程组的集合。

        1.5实现效果

        1. 守护进程自成立一个进程组和会话组,也就是PID、PGID、SID是一样的,而且该进程的父进程只能是systemd,不能是终端。

        2. 没有控制终端,也就是说TTY变成?

        1.6守护进程的创建步骤

        1.创建子进程,父进程退出

        备注: 第一步完成之后,子进程就在形式上做到了与终端脱离关系。

        2.在子进程中创建新的会话

                创建之后,PID、PGID和SID都一样了。

        

        3.改变当前目录为根目录

        4.重设文件权限掩码

                为啥要设置文件掩码?文件掩码是指文件权限中被屏蔽掉对应位,把文件掩码设置为0,可以增加该守护进程的灵活性。

        5.关闭文件描述符

        整体代码

         2、UNIX平台进程通信方式

        常用的进程间通信方式:

        传统的进程间通信方式:有名管道、无名管道和信号

        System V IPC对象:共享内存、消息队列和信号灯

        BSD:套接字(socket)

                2.1 无名管道

                特点:

                (1)只能用于具有亲缘关系(父子进程、兄弟进程)的进程之间的通信

                (2)半双工的通信方式,具有固定的读端和写端

                (3)管道可以看成一种特殊的文件(内核中的一块文件)

 

 

         管道是基于文件描述符的通信方式。当一个管道建立时,他会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,fd[1]固定用于写管道。

为什么无名管道只能用于具有亲缘关系之间的通信?

       父进程建立了管道,获得了文件描述符,子进程继承了父进程的文件描述符(fd[0]、fd[1])

        注意:(1)当管道中无数据时,读操作会阻塞;(2)向管道中写入数据时,Linux将不保证写入的原则性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞;(3)只有在管道的读端存在时,向管道中写入数据才有意义,否则向管道中写入数据的进程将收到内核传来的SIGPIPE信号(通常Broken pipe错误)。 

        完成代码:

        

         测试管道破裂:        

                 2.2有名管道

                特点:(1)无名管道只能用于具有亲缘关系的进程之间,这就限制了无名管道的使用范围。(2)有名管道可以使互不相关的两个进程相互通信。有名管道可以通过路径名来指出,并切在文件系统中可见。(3)进程通过文件IO来操作有名管道。(4)有名管道遵循先进先出的规则(5)不支持如lseek()操作。

                写端:

        

                读端:

        

总结:

管道文件的存在的意义

进程1创建并打开有名管道得到了一个内存文件(管道文件)+文件描述符。

进程2通过进程1创建的管道文件就可以得到一个同样的文件描述符,最终进程1和进程2就可以通信了。

无名管道:因为父进程创建并打开管道,得到了管道文件描述符,而子进程可以继承父进程的文件描述符,所以就可以进行通信了。

注意:当只有读端的时候,系统会阻塞,直到一个进程(包括自己)以另一种方式打开管道

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值