进程与线程

1.进程

1.1 什么是进程?

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

1.1.1如何查看进程

在Linux下查看进程有以下几种方法:

  1. ps aux
  2. ps -ef
  3. top
  4. pstree
  5. ps axj

1.1.2进程和程序的区别

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

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

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

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

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

为什么要有虚拟内存?

        多任务、安全

1.1.4进程的类型

(1)交互进程:该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。

(2)批处理进程:该类进程不属于某个终端,它被提交到一个队列中以便顺序执行。

(3)守护进程:该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束。

1.1.5进程运行状态

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

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

        可中断

        不可中断

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

(4)僵死态:这是一个已终止的进程,但还在进程向量数组中占有一个task_struct结构体。

为了更好的管理Linux所访问的资源,系统在内核头文件include/linux/sched.h定义了进程控制块(PCB)结构体task_struct来管理每个进程的资源

内核空间进程资源即PCB相关的信息,包括进程控制块本身,打开的文件表项、当前目录、当前终端信息、线程基本信息、可以访问内存地址空间、PID、PPID、UID、EUID等,也就是说,内核通过PCB结构体可以访问到进程的所有资源信息

(5)死亡态

进程状态图:

1.1.6进程的模式

1.2进程相关的系统调用

1.2.1创建进程:fork

        注意:fork之后,父进程和子进程存在资源竞争的关系,谁先调度由调度算法来决定。

1.2.2获取进程的进程号和父进程号:getpid,getppid

1.2.3进程的退出

exit、 _exit  、return(主函数的return)

需要注意的是exit()会刷新缓冲区,而_exit()不会刷新缓冲区!

1.2.4孤儿进程

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

1.2.5僵尸进程

子进程先退出,父进程没有及时回收子进程的资源(PCB结构体)(没有查看子进程的退出状态),此时就成为了僵尸进程。

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

1.2.6防止僵尸进程的出现:wait(),waitpid()

        子进程退出时父进程及时回收子进程的资源,可以调用wait或者waitpid。

1.2.6.1wait

1.2.6.2waitpid

1.2.7exec函数族

l:list 以列表的形式传参

v:vector 数组

p:path 系统会自动从环境变量“$PATH”所包含的路径中进行查找

1.3守护进程

1.3.1守护进程的特点

  1. 从系统启动开始运行,系统关闭时停止运行
  2. 后台进程,与终端无关

1.3.2实现守护进程:

(1)不能和终端具有亲缘关系

(2)与终端无关,也就是要把控制终端变成?

1.3.3进程组和会话组

1.3.4守护进程的创建步骤

(1)创建子进程,父进程退出。          备注:从形式已经脱离了终端。

(2)在子进程中创建新会话。                控住终端变成  “   ?”。   

pid_t setsid();

(3)改变当前目录为根目录                     防止用户误删。   

           int   chdir();

(4)重设文件权限掩码                      提高代码的灵活性 , 安全

mode_t  umask();

(5)关闭文件描述符

1.4通信相关概念

1.4.1通信的模式

单工:A-->B (键盘输入)

半双工:A--->B 或者 B--->A (对讲机)

双工:A--->B 同时 B-->A(打电话)

同步:

异步:

1.4.2通信方式

1.5管道

1.5.1无名管道

1.5.1.1相关概念

1.5.1.2创建无名管道

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

无名管道没有名字,不同的进程无法获取同一个文件描述符,具有亲缘关系的进程之间可以继承,从而得到同一个文件描述符。

注意:

(1)当管道中无数据时,读操作会阻塞

(2)向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将会一直阻塞。

(3)只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIGPIPE信号(通常Broken pipe错误)-->管道破裂

1.5.1.3测试管道破裂

1.5.2有名管道

1.5.2.1相关概念

1.5.2.2创建有名管道

1.6信号

1.6.1相关概念

1.6.2信号安装or信号注册函数

1.6.2.1忽略信号
1.6.2.2采用默认操作

1.6.2.3自定义信号处理函数

1.6.3闹钟函数:alarm

alarm()也称为闹钟函数,它可以在进程中设置一个定时器。当定时器指定的时间到时,内核就向进程发送SIGALARM信号。

1.6.4进程挂起:pause

pause()函数是用于将调用进程挂起直到收到信号为止。

1.6.5发送信号给进程或进程组:kill

1.6.6进程向自己发送信号:raise

1.7共享内存

1.7.1相关概念

SystemV提供的IPC机制主要由消息队列、共享内存、信号量3种机制。和文件一样,IPC在使用前必须先创建,每种IPC都有特定的生产者、所有者和访问权限。使用ipcs命令查看当前系统正在使用的IPC工具。

1.7.2共享内存的创建步骤

(1)创建/打开共享内存

(2)映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问

(3)撤销共享内存映射

(4)删除共享内存对象

1.7.3只用信号实现同步

写端:

读端:

1.8有名信号量

有名信号量:进程间的同步

无名信号量:线程间的同步

1.8.1创建有名信号量

1.8.1.1sem_open

1.8.1.2P操作和V操作

sem_wait( ):P操作 -1

sem_wait在信号量大于0时,它将这个信号量的值减1,若信号量的值为0,sem_wait将会阻塞

sem_post( ):V操作 +1

sem_post相当与V操作,它将信号量的值加1,同时唤醒等待的进程

1.8.1.3sem_close

1.9消息队列

1.9.1相关概念

        注意:消息类型不能为0!

1.9.2消息队列的创建步骤

发送端:

        1.创建并打开消息队列

        2.添加消息

        3.接受消息

        4.删除消息队列

2.线程

2.1线程的相关概念

2.2创建线程:pthread_create

注意:线程之间也存在资源竞争的关系!

2.3线程的等待函数:pthread_join

2.4将子线程设置为游离态:pthread_detach

2.5线程的退出函数:pthread_exit

3.多线程

3.1同步

3.1.1初始化:sem_init

3.1.2P/V操作:sem_wait,sem_post

sem_wait( ):P操作 -1

sem_wait在信号量大于0时,它将这个信号量的值减1,若信号量的值为0,sem_wait将会阻塞

sem_post( ):V操作 +1

sem_post相当与V操作,它将信号量的值加1,同时唤醒等待的进程

注意:也可以保护临界资源的完整性,而且实现同步

3.2互斥

3.2.1步骤

  1. 创建锁:pthread_mutex_t
  2. 初始化锁:pthread_mutex_init
  3. 上锁:pthread_mutex_lock
  4. 解锁:pthread_mutex_unlock
  5. 销毁锁:pthread_mutex_destroy

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值