Linux理论上可以创建多少个进程?
进程的pid使用pid_t表示的,为short类型变量(2字节),因此可以支持32768(2^15)个进程
一个进程可以创建多少个线程?
创建一个线程会占用多少内存,取决去分配给线程的调用栈大小。
ulimit -s命令可以查看(一般为8-10M)
一个进程的虚拟内存大小事4G,留给用户的只有3G。
因此进程最多可以创建的线程数是根据分配给调用栈的大小,以及操作西戎(32未,64位)共同决定的
进程与线程的联系与区别?
协程是线程内部调度的基本点位,线程是程序执行的最小单位,进程是操作系统分配资源的最小单位
一个进程可以有多个进程组成,线程是进程中代码的不同志雄路线
进程之间相互独立,同一进程下的线程之间共享程序的内存空间
进程的创建需要系统分配内存和CPU开销比线程大
线程锁有哪些类型?
互斥锁、读写锁、条件变量、自旋锁
线程同步的5种方式:
信号量:多线程访问前需要进程申请资源(P),访问结束释放资源(V)
互斥锁:同一时间只有一个线程访问该资源
读写锁:允许多线程读,只能一个线程写
自旋锁:忙等待锁,用于锁占用时间比较短。
条件变量:一个线程可以等待某个条件满足
进程间通信方式(IPC)?
管道:
消息队列
信号量
共享内存 :int shmget()
信号:只用于通知接受进程某个时间已经发行
套接字
生产生与消费者模型(321原则)
一个缓冲区,两个角色、三种关系
生产者与消费者之间的同步与互斥关系
生产者与生产者之间的互斥关系
消费者与消费者之间的互斥关系
可以借助循环队列来作为交易场所,用信号量实现同步与互斥关系
总结:
生产者->先wait(_empty) wait(_mutex) 再 post(_mutex) post(_full)
消费者->先wait(_full) wait(_mutex) 再 post(_mutex) post(_empty);
_empty表示缓冲区是否还有位置 _mutex表示锁
避免死锁的方法?
- 以确定的顺序获得锁
- 超时放弃
- 检测死锁,发现有进程死锁后,立刻把它从死锁中解脱出来
进程切换与线程切换的区别?
- 进程切换主要涉及到虚拟地址空间的切换。线程共享进程所在的虚拟地址空间,不涉及虚拟地址空间的切换
- 进程切换包含指令和页表的切换,线程只涉及指令的切换
父子进程间那些资源是共享的,那些是独有的?
不共享数据段和堆栈段,其他的比如正文段和文件共享
建立TCP服务器的各个系统调用过程?
close( )与shutdown( )区别?
shutdown可以指定在某个方向上终止链接,通过指定标志位:SHUT_RD、SHUT_WR、SHUT_RDWR。而close是两个方向上的终止链接(关闭读和写)
shutdown不管引用计数,直接发送FIN终止链接。close会将描述符的引用计数减一,如果引用计数变为0,就关闭描述符,发送FIN
因此多线程下操作同一个socket描述符,一个线程调用shutdown会使其他线程无法使用这个描述符,而调用close不会影响到其他线程。
总结:
- 使用 close 函数关闭连接有两个需要明确的地方。close 函数只是把套接字引用计数减 1,未必会立即关闭连接;
- close 函数如果在套接字引用计数达到 0 时,立即终止读和写两个方向的数据传送
- 在大多数情况下,我们会优选 shutdown 来完成对连接一个方向的关闭,待对端处理完之后,再完成另外一个方向的关闭
- shuutdown关闭读不会给对方发FIN,只有关闭写才会发FIN
线程池的优点?
- 降低资源消耗:通过重复利用已创建的线程,降低线程创建和销造成的消耗
- 提升相应速度:当任务达到时,不需要等待线程创建就能立即执行
- 便于管理:使用线程池可以统一分配、监控和调优
线程池实现原理?
先了解几个名词:
工作线程:执行任务的线程
核心线程:线程池维护的最小线程数量,不会被回收
工作队列:存放待执行的任务
工作原理:
- 首先判断线程池里面的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下一个流程。
- 判断线程池工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在工作队列中,如果工作队列满了,则进入下个流程
- 判断线程池的线程是否都处于工作状态中,如果没有则创建一个新的工作线程来执行任务。如果已经满了则交给饱和策略来处理这个任务。
服务端如何实现并发(2种方法)?
多线程:每次accept获得一个句柄,就创建一个线程去处理链接。
缺点:耗费CPU,创建线程的消耗太大
多路IO复用:对于处于闲置状态或者处于IO阻塞的状态,把阻塞的socket放置一边,来避免等待所带来的资源耗费,即非阻塞IO的概念
通过不断轮询多个socket,当其中的某个socket准备好了,数据就返回,否则整个进程就继续阻塞。