linux常见命令
netstat -a 获取所有连接(包括tcp)
https://blog.csdn.net/namechenfl/article/details/90767222
df -h 查看磁盘各个分区占用情况
iftop -i (网卡号) 查看网卡带宽占用情况
nethogs (网卡号) 查看每个进程占用带宽情况
进程 之间通信:
本地进程间的通信(IPC)
管道(无名管道,内存中的文件,固定读写端):
它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
FIFO(也称命名管道,一种文件类型,存在文件系统中)
FIFO可以在无关的进程之间交换数据,与无名管道不同。
FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中
消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
信号量
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
特点
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的 PV 操作(操作系统中的一种同步机制),程序对信号量的操作都是原子操作。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
支持信号量组。
共享内存
共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
1、特点
共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
五种通讯方式总结
1.管道:速度慢,容量有限,只有父子进程能通讯
2.FIFO:任何进程间都能通讯,但速度慢
3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题
4.信号量:不能传递复杂消息,只能用来同步
5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存
共享内存
python
mutlprocessing 或者 mmap模块
内存的结构
https://blog.csdn.net/qq_34793133/article/details/82252211
分段 分页(解决进程隔离)
https://www.cnblogs.com/fengliu-/p/9243004.html
文件读写
打开文件后 将文件内容加载到内存 产生文件描述符
读文件
1、进程调用库函数向内核发起读文件请求;
2、内核通过检查进程的文件描述符定位到虚拟文件系统的已打开文件列表表项;
3、调用该文件可用的系统调用函数read()
3、read()函数通过文件表项链接到目录项模块,根据传入的文件路径,在目录项模块中检索,找到该文件的inode;
4、在inode中,通过文件内容偏移量计算出要读取的页;
5、通过inode找到文件对应的address_space;
6、在address_space中访问该文件的页缓存树,查找对应的页缓存结点:
(1)如果页缓存命中,那么直接返回文件内容;
(2)如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页;重新进行第6步查找页缓存;
7、文件内容读取成功。
写文件
前5步和读文件一致,在address_space中查询对应页的页缓存是否存在:
6、如果页缓存命中,直接把文件内容修改更新在页缓存的页中。写文件就结束了。这时候文件修改位于页缓存,并没有写回到磁盘文件中去。
7、如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页。此时缓存页命中,进行第6步。
8、一个页缓存中的页如果被修改,那么会被标记成脏页。脏页需要写回到磁盘中的文件块。有两种方式可以把脏页写回磁盘:
(1)手动调用sync()或者fsync()系统调用把脏页写回
(2)pdflush进程会定时把脏页写回到磁盘
同时注意,脏页不能被置换出内存,如果脏页正在被写回,那么会被设置写回标记,这时候该页就被上锁,其他写请求被阻塞直到锁释放。
文件描述符和inode区别
https://www.cnblogs.com/fengfengyang/p/9609130.html
网络进程间的通信
https://blog.csdn.net/pashanhu6402/article/details/96428887
我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是我为什么说“一切皆socket”。
socket基于tcp/ip
线程间的通信
java
使用 volatile 关键字
基于 volatile 关键字来实现线程间相互通信是使用共享内存的思想,大致意思就是多个线程同时监听一个变量,当这个变量发生变化的时候 ,线程能够感知并执行相应的业务。这也是最简单的一种实现方式
使用Object类的wait() 和 notify() 方法
wait和 notify必须配合synchronized使用,wait方法释放锁,notify方法不释放锁
使用JUC工具类 CountDownLatch
相当于也是维护了一个线程间共享变量state
基本LockSupport实现线程间的阻塞和唤醒
LockSupport 是一种非常灵活的实现线程间阻塞和唤醒的工具,使用它不用关注是等待线程先进行还是唤醒线程先运行,但是得知道线程的名字。
PV操作
操作系统中的一种同步机制,实现对于并发进程中临界区的管理。
堆栈
http://wenda.tianya.cn/question/5dde6d76bbb05f0e
lru
如何构造线程池,它的参数,饱和策略?
线程都有哪些状态?
新建状态、就绪状态、运行状态、阻塞状态及死亡状态
创建多少线程合适
https://www.jianshu.com/p/f30ee2346f9f
多线程上下文切换
https://www.cnblogs.com/williamjie/p/9466941.html
I/O 复用模型
1 阻塞IO 用户进程一直等待内核把数据准备好,期间不干别的事
2 非阻塞IO 如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error 用户进程需要不断的主动询问kernel数据准备好了没有
3 多路复用IO select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程
4 异步IO 用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了
select原理
linux一切皆文件 每个socket都是一个文件 linux用文件描述符管理文件
多个文件描述符中 被监听的文件描述符编号被记录在一个bitmap中(位图),并且记下当前最大编号(防止多余轮询),传给select函数。bitmap默认为1024位。
select将bitmap拷贝至内核态,内核去判断当前bitmap中标记的文件描述符是否有数据。如果有,将其在bitmap上置位,返回给用户态。否则会一直阻塞。
内核拿到bitmap后 轮询看哪个文件描述符被置位了,然后去接收相应的数据。
缺点:
1 只有1024位。
2 bitmap被置位而不能复用。每次轮询都需要对bitmap重新赋值。
3 用户态->内核态的切换。
4 不断轮询 O(n)的复杂度。
poll原理
跟select相比
1 用数组代替bitmap 所以不只1024的长度(解决1)
2 内核每次对数组中的一个结构体变量进行赋值,所以数组可以复用(解决2)
3、4未被解决
epoll原理
改进:
1 epoll_create创建一个数据结构,内部存储文件描述符和其对应事件(类似poll)
2 共享空间存储 没有用户态和内核态的切换
3 有数据会将其重排至最前面,并返回有几个有数据的文件描述符(底层红黑树,重排效率高)
也有人说开辟单独空间存放有数据的文件描述符
https://blog.csdn.net/armlinuxww/article/details/92803381
优势:
epoll分离了把进程添加到socket等待队列和阻塞进程两个步骤,添加了eventpoll中间层管理就绪的socket,直接回调被epoll_wait函数阻塞的进程,时间复杂度O(1)
select把所有socket存在一起,每次遍历所有socket看哪个准备好了数据,在唤起进程,并删除其他socket的等待队列,两次遍历O(n)
Linux中五种IO模型
如何实现一个同步非阻塞的请求
实现进程同步的机制有什么
信号量的实现机制
共享锁和排他锁
实现一个读写锁
设计一个无锁队列
协程的原理
select poll epoll的区别
https://www.cnblogs.com/Anker/p/3265058.html
内核pcb
https://blog.csdn.net/mm_hh/article/details/70056519
详解PCB
https://blog.csdn.net/jiaomubai/article/details/89683772?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
软连接与硬链接
https://www.cnblogs.com/crazylqy/p/5821105.html
死锁
线程状态
-
新建(NEW):新创建了一个线程对象。
-
可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
-
运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
-
阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
5. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
进程状态
运行态:该进程正在执行。
就绪态:进程已经做好了准备,只要有机会就开始执行。
阻塞态(等待态):进程在某些事情发生前不能执行,等待阻塞进程的事件完成。
新建态:刚刚创建的进程,操作系统还没有把它加入到可执行进程组中,通常是进程控制块已经创建但是还没有加载到内存中的进程。
退出态:操作系统从可执行进程组中释放出的进程,或由于自身或某种原因停止运行。
时间片
是分时操作系统分配给每个正在运行的进程微观上的一段CPU时间(在抢占内核中是:从进程开始运行直到被抢占的时间)。现代操作系统(如:Windows、Linux、Mac OS X等)允许同时运行多个进程 —— 例如,你可以在打开音乐播放器听音乐的同时用浏览器浏览网页并下载文件。事实上,虽然一台计算机通常可能有多个CPU,但是同一个CPU永远不可能真正地同时运行多个任务。在只考虑一个CPU的情况下,这些进程“看起来像”同时运行的,实则是轮番穿插地运行,由于时间片通常很短(在Linux上为5ms-800ms),用户不会感觉到。
中断 缺页中断
锁
互斥锁 条件锁 读写锁 自旋锁
https://www.zhihu.com/question/66733477
读写锁
https://blog.csdn.net/qq_37685457/article/details/89855519
重量级锁
完全mutex保证:
内核状态的互斥量(mutex)保证互斥
java jdk1.4 自旋(给定次)+mutex:
java jdk1.6 自旋自适应次+mutex:
自旋锁
1 忙等待锁
2 同时只有一个没和代码路径可以获得
3 要求spinlock持有者尽快完成临界区任务 不得睡眠
4 可以在中断上下文中使用
优点(全程在用户态)
缺点(while 1 + cas 消耗cpu)
ps:cas是原子操作 代替 == 和赋值(非原子操作)
公平锁 非公平锁
悲观锁 乐观锁 意向锁
意向锁:意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。
意向共享锁(Intent Share Lock,简称IS锁)
意向排它锁(Intent Exclusive Lock,简称IX锁)
共享意向排它锁(Share Intent Exclusive Lock,简称SIX锁)
悲观锁
共享锁:共享 (S) 用于不更改或不更新数据的操作(只读操作),如 SELECT 语句。
如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。
排他锁:用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。
如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
虚拟内存与物理内存的映射方式
https://www.cnblogs.com/panchanggui/p/9288389.html
mmap
首先mmap对应文件磁盘 读取时 首先加载到物理内存中 将内核空间和用户空间的虚拟内存都映射到这个物理地址中 实现内核 用户共享内存
在用户空间中 存放在libraries空间 省去内核空间和用户空间互相拷贝 实现0拷贝的一种方式
调度算法
https://www.cnblogs.com/kxdblog/p/4798401.html
缓存屏障
https://blog.csdn.net/zhangxinrun/article/details/7103709