- 博客(18)
- 收藏
- 关注
原创 3.2.1 原子操作CAS与锁实现
在不同的 CPU 架构上,这些模型的具体实 现方式可能不同,但是 C++11 帮你屏蔽了内部细节,不用考虑内存屏障,只要符合上面的使用规则,就能得到想要的效果。这里a、b线程同时进行,a线程中y变量写入用了memory_order_release操作,b线程中y变量用了memory_order_acquire,这就保证了在b线程中必须先获取到y的写入之后才会触发后面的x获取操作,这就使Z一定为1,如果换成released松散操作的话,cpu可能对两个线程中的指令进行重排,结果可能就不为1了。
2025-04-02 19:51:22
788
原创 3.1.2 内存池的实现与场景分析
代码长期运行之后,由于使用传统的内存分配方法(malloc,free)在频繁的内存分配和释放过程中会导致内存碎片化,引起coredump。而且频繁的内存分配和释放过程频繁的系统调用会导致较大的系统开销,这时候就需要使用内存池进行统一的管理,预先分配一块连续的内存空间,并在需要时直接从中取出或回收,避免频繁进行系统调用,从而提高了程序性能。这一句,前面表示把ptr强行转换为指向char* (字符串指针类型)的指针,然后解引用,使得分配出来的内存块前四个字节储存下一个内存块的首地址。
2025-03-26 20:15:01
229
原创 3.1.1 手写线程池与性能分析
内部会创建一个任务队列,用于存储待执行的任务,并初始化线程池中的线程。线程池的线程会等待并执行队列中的任务。1.线程(生产者,如主线程):负责生成任务(如用户请求、IO事件等),并将任务及其上下文(数据、执行函数)放入任务队列。线程池(消费者):由一组预先创建的线程构成,这些线程从队列中取出任务并执行任务函数,实现任务的异步处理。每个工作线程会不断从任务队列中获取任务并执行,直到线程池关闭或队列为空。任务队列是一个线程安全的队列,负责存储等待执行的任务。该函数会将任务添加到线程池的任务队列中。
2025-03-24 16:39:31
571
原创 9.1.4 KV存储的性能测试
kv存储查询的方式比较简单,从键映射到值,不需要复杂的查询语句,而且正因为查询方式为键到值映射,时间复杂度为o(1),且kv存储的可扩展性比较好,通过增加节点就可以增加存储的数据,在不需要数据的时候可以及时的释放内存。对于 io_uring,虽然它本身能在单线程中获得很高性能,但在极高并发场景下,可以将提交队列/完成队列分片,由多个线程并行处理不同 I/O 任务。保证覆盖到每个实现的协议接口,例如kv_create、kv_set、kv_get等,设计循环记录开始结束时间,计算qps。7.测试用例如何实现?
2025-03-20 15:37:18
275
原创 9.1.3 内存池的使用与LRU的实现
命令:./testcase 192.168.202.129 2000 1 红黑树3万次测试。主要实现了create,destory,set,get,del,mod,exist。
2025-03-19 15:13:45
180
原创 9.1.1 kv存储的架构设计
1.本节课主要是解决kv存储的基础架构网络协议部分,把reactor,io_uring和ntyco的协议调通。先看reactor代码:上述的reactor代码改造后,kv存储的请求kvs_request、kvs_response被放在了recv_cb send_recv里。
2025-03-17 15:14:22
253
原创 9.1.2 网络同步与事务序列化
这里的recv_cb里面添加了kvs_request,send_cb里添加了kvs_response(响应),server从client获取kv存储请求(kvs_reques),返回处理结果(kvs_response)。2.这节课,我们第一步主要实现协议设计:下面图中client向server发送请求,server解读请求并处理,返回结果。这里的循环成功输出了分割后的tokens,证明协议实现成功,把client输入的字符通过kvs_split_token分割。kvstore.c里实现。
2025-03-13 10:40:41
299
原创 2.5.3 windows异步机制iocp
iocp:先来看具体的阻塞式io的工作模式:阻塞式io有四个问题:连接的建立/断开,数据的接收/发送,这四个都不知道何时发生,所以内核只能阻塞在这个地方等待事件发生。我们再回过头来看reactor与io_cp,就会发现两者的不同之处:(1)reactor是同步的io,异步的事件。reactor在进行io操作时候是异步的,而事件完成的通知是同步的,通过epoll_wait监视事件的状态(2)而iocp(proactor)则是异步的io操作,应用程序通过(如WSARecv。
2025-03-07 15:10:36
795
原创 2.5.2 io_uring的使用场景
可以看到,io_uring比epoll性能要好,但好的有限。原因是epoll的逻辑是同步的,内核监控fd产生变化的时候才进行下一步操作,而io_uring是异步的,只需要把事件注册到待处理队列里面去,通过环形队列减小系统的开销。测试结果,发512bytes的包情况下,io_uring和epoll的区别:上io_uring下epoll。2.-n req -t threadum -c connection(请求数 、线程数 、连接数)1.实现tcp client连接。
2025-03-04 20:11:05
382
原创 2.5.1 与epoll媲美的io_uring
read\write recv\send都是同步的io,工作流都如上所示:client向server发起请求,等待server返回数据,在这期间程序是停止在这一步的。a_read把数据push到submit queue里,worker从submit queue里负责取数据去处理,把完成的结果存放到complete queue里。4.epoll和io_uring的不同:epoll设置过事件后就会一直存在,不需要重新设置,io_uring事件处理完后需要重新设置事件。这就是本节课所讲的io_uring。
2025-03-01 14:09:21
247
原创 2.4.4 手把手设计实现epoll
当内核IO准备就绪的时 候,则会执行epoll_event_callback 的回调函数,将epitem添加到list中。如果条件满足,socket 会通过内部机制(如调用 __wake_up() 或 wake_up_interruptible())将等待在 epoll_wait 上的进程唤醒,并将该 socket 对应的事件添加到 epoll 的就绪列表中。当网络设备接收到数据后,通过中断机制唤醒内核,数据被传递到协议栈相应的层(如 TCP 层),进而更新对应 socket 的状态(如有数据可读)。
2025-02-27 20:48:19
540
原创 2.4.3 tcp/ip定时器与滑动窗口
上节课已经实现了从网络助手往sever发包,这节课要实现从server往网络助手发包,建立连接(即三次握手的过程)。详情参考tcp.c。
2025-02-23 12:07:28
186
原创 2.4.1 用户态协议栈设计实现
协程目的:recv/send函数是一个同步的操作过程-->改成异步的操作过程,内核里面没有数据可读的时候,可以等一等,但不影响其他fd的recv/send过程。整个NtyCo做的就这一个事情,涉及到了协程的定义,hook的实现。(很重要,建议看一下)
2025-02-19 18:18:26
919
原创 2.2.2 Posix API与网络协议栈
a.创建一个int类型的fdb.内部有一个TCB控制块。TCB 是一个内核数据结构,包含多个字段来记录 TCP 连接的状态和相关信息。1234580初始值为 1001初始值为 2001操作系统通过五元来查找对应的TCB。
2025-01-15 11:55:07
841
原创 2.2.1 服务器百万并发实现(实操)
Reactor 模式的原理在于事件驱动和回调机制,通过一个中央调度器(通常是事件循环)来监听事件的发生,并在事件发生时分发给对应的处理器(回调函数)。在这里使用了一个循环开辟20个端口,因为一个端口建立的连接数量最大是65536-1024,这里设置好fd和回调函数后用set__event接口调用epoll。这一步是阻塞的,但不会阻塞整个程序,只阻塞等待事件的线程。将感兴趣的事件(如可读、可写)注册到epoll,并为每个事件绑定对应的回调函数。当某个事件就绪时,epoll_wait返回就绪事件列表。
2025-01-08 15:30:51
249
原创 2.1.1 网络io与io多路复用select/poll/epoll(续)
上一篇的代码做出小改进,打印listenfd,clientfd:运行后:这张图有三个点需要注意:(1)系统创建listenfd的时候是从3开始的,因为0,1,2已经被系统占用用作终端输入、输出、错误的套接字。(2)红框里断开客户端后立刻连接,系统还没有回收4,所以安排了7作为套接字(3)蓝框里是断开后经过了TIMEWAIT后再连接的,系统已经回收了4,就会再次分配4。上面的代码优点:代码逻辑简单易于实现,缺点:1客户端1线程,浪费资源,不利于百万级的并发。
2025-01-06 15:43:27
934
原创 2.1.1 网络io与io多路复用select/poll/epoll
listen是在服务器端调用,用于将套接字(socket)设置为监听状态。这个操作创建一个监听文件描述符,用来监听客户端的连接请求。listen本身并不会建立实际的连接,它只让操作系统知道这个套接字会用于被动接受连接。这个监听套接字在服务器运行期间会一直有效,并通常唯一。当有客户端发起连接请求时,accept被调用,它会从监听套接字中取出一个连接请求,并创建一个新的文件描述符(称为连接套接字或通信套接字),这个 fd 专用于与客户端通信。accept创建的文件描述符用于与特定的客户端进行数据传输。
2025-01-04 11:46:02
750
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人