赞
踩
https://linuxreviews.org/Why_is_printk()_so_complicated%3F
特点
它是一个多生产者,单个或多个消费者组成的循环缓冲区。
- struct kfifo {
- unsigned char *buffer;
- unsigned int size;
- unsigned int in;
- unsigned int out;
- spinlock_t *lock;
- };
- 其中buffer指向存放数据的缓冲区,
- size是缓冲区的大小,
- in是写指针下标,
- out是读指针下标,
- lock是加到struct kfifo上的自旋锁(上面说不加锁不是这里的锁),
- 防止多个进程并发访问此数据结构。
- 当in==out时,说明缓冲区为空;
- 当(in-out)==size时,说明缓冲区已满。
当然现在我们面对的大多是多线程的协同工作,
对于日志记录来说,倘若采取传统的加锁机制访问我们的存储文件,这些线程将在获得和释放锁上花费了大部分的时间,
所以采取循环缓冲区会是一个不错的办法。
通过使得每个线程将数据写入到它自己的内存块,就可以完全避免同步问题 【不懂这个】
- 生产者不能被缓慢的消费者所阻挡。取而代之的是,生产者只是简单地按照他们想要的速度写作,而消费者则尽其所能跟上
在通常情况下,环形缓冲区的读用户仅仅会影响读指针,而写用户仅仅会影响写指针。
如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以保证数据的正确性。
如果有多个读写用户访问环形缓冲区,那么必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。
在最典型的生产者消费者模型中,如果引入环形队列,那么生成者只需要生成“东西”然后放到环形队列中即可,而消费者只需要从环形队列里取“东西”并且消费即可,没有任何锁或者等待,巧妙的高效实现了多线程数据通信。
一般应用于需要高效且频繁进行多线程通信传递数据的场景,例如:linux捕包、发包等等,(linux系统中对PACKET_RX_RING和PACKET_TX_RING的支持实质就是内核实现的一种环形队列)
https://hedzr.com/algorithm/golang/ringbuf-01-intro/
https://segmentfault.com/a/1190000016329997
- 环形队列是一种 FIFO 数据结构。
- 它和普通 FIFO 队列数据结构的不同就在于队尾连接着队首,
- 当入列元素位于队尾时,该元素将被回绕并放在队首的位置,
- 从而完成有界性限定。而普通的 FIFO 队列总是增长队尾以入列新元素,
- 并不限制队列的有效长度。
-
- 环形队列具有先天优势,无需数据搬移
- https://github.com/smallnest/ringbuffer
https://ylgrgyq.github.io/2017/07/23/linux-receive-packet-1/
Linux kernel里面从来就不缺少简洁,优雅和高效的代码
. 2的次幂
- Linux内核中kfifo
- 实现技巧,主要集中在放入数据的put
- 方法和取数据的get方法。代码如下:
-
- 为什么kfifo实现的单生产/单消费模式的共享队列是不需要加锁同步的呢?
- https://blog.csdn.net/chen19870707/article/details/39899743
https://blog.csdn.net/chen19870707/article/details/39899743
https://unix.stackexchange.com/questions/198178/what-are-the-concepts-of-kernel-ring-buffer-user-level-log-level
https://zhuanlan.zhihu.com/p/118158992
https://www.jianshu.com/p/e6162bc984c8
想看能不能完整梳理一下收消息过程。从 NIC 收数据开始,到触发软中断,交付数据包到 IP 层再经由路由机制到 TCP 层,最终交付用户进程
课堂练习如果你对 TCP 协议的结构不太熟悉,可以使用 tcpdump 命令截取一个 TCP 的包,看看里面的结构。
UDP 是面向数据报的,一个一个地发送。
TCP 是可以提供流量控制和拥塞控制的,既防止对端被压垮,也防止网络被压垮
在内核中,为每个 Socket 维护两个队列。
一个是已经建立了连接的队列,这时候连接三次握手已经完毕,处于 established 状态;
一个是还没有完全建立连接的队列,这个时候三次握手还没完成,处于 syn_rcvd 的状态。
struct sk_buff 是存储网络包的重要的数据结构,在应用层数据包叫 data,
在 TCP 层我们称为 segment,
在 IP 层我们叫 packet,
在数据链路层称为 frame。
在 struct sk_buff,首先是一个链表,将 struct sk_buff 结构串起来。
网卡作为一个硬件,接收到网络包,应该怎么通知操作系统,这个网络包到达了呢?
没错,我们可以触发一个中断
如果一个网络包到来,触发了硬件中断,就会调用 ixgb_intr,这里面会调用 __napi_schedule。
我们知道,软中断 NET_RX_SOFTIRQ 对应的中断处理函数是 net_rx_action。
这两个工作都在 poll 中完成,上面说过 poll 是个 driver 实现的函数,所以每个 driver 实现可能都不相同。但 poll 的工作基本是一致的就是:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。