一、IO多路复用的原理
将多个阻塞任务的文件描述符,统一放到一个检测容器中,然后用一个阻塞函数进行管理,如果检测容器有一个或多个文件描述符对应的事件产生,就会解除阻塞,进而去执行相应的函数。
二、实现IO多路复用的方式
select、poll、epol
区别:
select,poll,epoll都是I/O多路复用机制,即能监视多个fd,一旦某fd就绪(读或写就绪),能够通知程序进行相应读写操作。 但select,poll,epoll本质都是同步I/O,因为他们都需在读写事件就绪后,自己负责进行读写,即该读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O实现会负责把数据从内核拷贝到用户空间。
select,poll需自己主动不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但它是设备就绪时,调用回调函数,把就绪fd放入就绪链表,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但select和poll在“醒着”时要遍历整个fd集合,而epoll在“醒着”的时候只需判断就绪链表是否为空,节省大量CPU时间,这就是回调机制带来的性能提升。
select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,且把current往等待队列上挂也只挂一次(在epoll_wait开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少开销。
三、数据库操作对应的函数有哪些
sqlite3_open
sqlite3_close
sqlite3_errmsg
sqlite3_errcode
sqlite3_exec
sqlite3_get_table
sqlite3_free_table
四、什么是僵尸进程
子进程退出,父进程不退出,且父进程不回收子进程的资源。此时子进程会变成僵尸进程。
注意:
- 僵尸进程本身就死掉的进程,无法再被kill
- 僵尸进程是有危害的:占用进程号,占用进程调度块,占用cpu资源等等,,,,,
- 僵尸进程必须回收!!!
回收僵尸进程的方式:
- 退出僵尸进程的父进程,僵尸进程的资源将由内核自动回收。
- wait/waitpid函数回收:阻塞形式会导致父进程无法正常执行自己的任务,非阻塞形式可能会收不到僵尸进程。
- 将wait/waitpid函数结合信号的方式回收:当子进程退出后,发送一个信号给父进程,通知父进程收尸
五、什么是孤儿进程
退出父进程,子进程不退出,此时子进程被1号进程(init进程)收养。
- 孤儿进程脱离终端控制,运行在后端
- ctrl+c无法杀死后端进程,孤儿进程可以用kill -9 killall -9杀死
- 孤儿进程是活着的进程,没有危害。
六、消息队列和共享内存的区别
消息队列的特点
- 消息队列需要打包,有特定的格式以及消息类型。
- 消息队列按照先进先出的原则,但是也可以限制消息类型读取,在限制消息类型后也需要按照先进先出的原则。
- 消息队列独立于进程,等进程结束后,消息队列以及其中的内容不会删除,除非重启操作系统或者手动删除。
共享内存的特点
- 共享内存可以通过映射,在用户空间直接获取到共享内存的首地址。用户只需要在用户空间通过操作地址,直接访问到共享内存
- 共享内存是 最高效的 进程间通信方式。
- 多个进程可以同时访问共享内存,修改其中的内容,所以共享内存其实是临界资源,需要注意进程间的同步互斥:
- 信号灯集
- 互斥锁
- 条件变量
- 信号灯
- 共享内存独立于进程,等进程结束后,共享内存以及其中的内容不会删除,除非重启操作系统或者手动删除。