7、创建子进程,fork函数详解?
- 函数原型
pid_t fork(void);
//void代表没有任何形式参数; - 除了0 号进程(系统创建的)之外,linux 系统中都是由其他进程创建的。创
建新进程的进程,即调用fork函数的进程为父进程,新建的进程为子进程。 - fork函数不需要任何参数,对于返回值有三种情况:
对于父进程,fork函数返回新建子进程的pid;
对于子进程,fork函数返回0;
如果出错,fork函数返回-1。
int pid=fork();
if(pid < 0){
//失败,一般是该用户的进程数达到限制或者内存被用光了
........
}
else if(pid == 0){
//子进程执行的代码
......
}
else{
//父进程执行的代码
.........
}
8、线程池和进程池?
8.1、线程池原理
为什么需要线程池?
- 大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的;
- 在传统的多线程服务器模型中是这样实现的:一旦有个请求到达,就创建一个新的线程,由该线程执行任务,任务执行完毕之后,线程就退出。这就是 ”即时创建,即时销毁” 的策略;
- 尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数非常频繁,那么服务器就将处于一个不停的创建线程和销毁线程的状态。这笔开销是不可忽略的,尤其是线程执行的时间非常非常短的情况。
线程池原理:
- 在应用程序启动之后,就马上创建一定数量的线程,放入空闲的队列中。这些线程都是处于阻塞状态,这些线程只占一点内存,不占用CPU;
- 当任务到来后,线程池将选择一个空闲的线程,将任务传入此线程中运行;
- 当所有的线程都处在处理任务的时候,线程池将自动创建一定的数量的新线程,用于处理更多的任务;
- 执行任务完成之后线程并不退出,而是继续在线程池中等待下一次任务;
- 当大部分线程处于阻塞状态时,线程池将自动销毁一部分的线程,回收系统资源。
线程池作用: 需要大量的线程来完成任务,且完成任务的时间比较短;对性能要求苛刻的应用。
8.2、内存池
内存池原理:
- 在软件开发中,有些对象使用非常频繁,那么我们可以预先在堆中实例化一些对象,我们把维护这些对象的结构叫“内存池”;
- 在需要用的时候,直接从内存池中拿,而不用重新实例化,在要销毁的时候,不是直接free/delete,而是返还给内存池;
- 把那些常用的对象存在内存池中,就不用频繁的分配/回收内存,可以相对减少内存碎片,更重要的是实例化这样的对象更快,回收也更快;
- 当内存池中的对象不够用的时候就扩容。
内存池优缺点:
- 内存池对象不是线程安全的,在多线程编程中,创建一个对象时必须加锁。
9、进程调度算法
1、 先来先服务 first-come first-serverd(FCFS)
-
非抢占式的调度算法,按照请求的顺序进行调度。
-
有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长。
2、 短作业优先 shortest job first(SJF)
- 非抢占式的调度算法,按估计运行时间最短的顺序进行调度。
- 长作业有可能会饿死,处于一直等待短作业执行完毕的状态。因为如果一直有短作业到来,那么长作业永远得不到调度。
3、最短剩余时间优先 shortest remaining time next(SRTN)
- 最短作业优先的抢占式版本,按剩余运行时间的顺序进行调度。 当一个新的作业到达时,其整个运行时间与当前进程的剩余时间作比较。
- 如果新的进程需要的时间更少,则挂起当前进程,运行新的进程。否则新的进程等待。
4、时间片轮转
- 将所有就绪进程按 FCFS 的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片;
- 当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。
时间片轮转算法的效率和时间片的大小有很大关系:
- 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。
- 而如果时间片过长,那么实时性就不能得到保证。
5、优先级调度
- 为每个进程分配一个优先级,按优先级进行调度。
- 为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。
6、多级反馈队列
- 一个进程需要执行 100 个时间片,如果采用时间片轮转调度算法,那么需要交换 100 次。
- 多级队列是为这种需要连续执行多个时间片的进程考虑,它设置了多个队列,每个队列时间片大小都不同,例如 1,2,4,8,…。进程在第一个队列没执行完,就会被移到下一个队列。
- 这种方式下,之前的进程只需要交换 7 次。每个队列优先权也不同,最上面的优先权最高。因此只有上一个队列没有进程在排队,才能调度当前队列上的进程。
可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。
10、Linux下进程间通信方式?
管道:
- 无名管道(内存文件):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程之间使用。进程的亲缘关系通常是指父子进程关系。
- 有名管道(FIFO文件,借助文件系统):有名管道也是半双工的通信方式,但是允许在没有亲缘关系的进程之间使用,管道是先进先出的通信方式。
共享内存:
- 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。
- 共享内存是最快的IPC方式, 它是针对其他进程间通信方式运行效率低而专门设计的。它往往与信号量,配合使用来实现进程间的同步和通信。
消息队列:
- 消息队列是有消息的链表,存放在内核中并由消息队列标识符标识。
- 消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点
套接字:
- 适用于不同机器间进程通信,在本地也可作为两个进程通信的方式。
信号:
- 用于通知接收进程某个事件已经发生,比如按下ctrl + C就是信号。
信号量:
- 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
- 它常作为一种锁机制,实现进程、线程的对临界区的同步及互斥访问。