核心内容摘要
大雷打狙免费入口官网:开启无限精彩,就在此刻!
在编写多线程并发服务器(Multi-threaded Server)时,最容易让新手“翻车”的一个细节就是如何将主线程接收到的文件描述符(File Descriptor, fd)正确地传递给子线程。
很多初学者会发现,明明代码逻辑看起来没问题,但当多个客户端同时连接时,消息却发错乱了(比如客户端A发的消息被服务器回传给了客户端B)。
本文将基于课堂笔记,深度解析这个经典的“内存共享陷阱”,并提供正确的解决方案。
问题背景:为什么不能直接传地址?
典型错误场景在主线程的while循环中,我们通常会这样做:调用accept()阻塞等待,返回一个新的文件描述符cfd。
调用pthread_create()创建子线程。
错误操作:将cfd的地址(cfd)作为参数传递给子线程。
原因深度剖析这涉及到了进程与线程的内存模型差异:进程(Process):拥有独立的虚拟地址空间。
修改一个进程的变量不会影响另一个进程(写时复制)。
线程(Thread):共享同一个进程的虚拟地址空间(堆、全局变量等)。
灾难发生的流程如下:时刻 T1:主线程accept成功,cfd变量被赋值为3(代表客户端 A)。
时刻 T2:主线程调用pthread_create,传入cfd。
时刻 T3:主线程继续循环,再次accept成功,cfd变量被更新为4(代表客户端 B)。
时刻 T4:子线程 A 开始运行,通过传入的地址cfd去读取数据。
此时它读到的是被修改后的值 4。
结果:子线程 A 本该服务客户端 A(fd=
,结果却拿到了 fd=4,导致它错误地与客户端 B 进行了通信,或者发生“串台”现象。
解决方案:构建描述符管理数组为了避免上述竞态条件(Race Condition),我们需要保证每个子线程拿到的文件描述符是存储在独立内存区域中的,互不干扰。
核心思路:定义一个全局结构体数组(或整型数组)。
主线程accept成功后,遍历数组找到一个“空闲位置”。
将cfd存入该位置。
将该数组元素的地址传递给子线程。
这样,即使主线程的cfd局部变量变了,数组中存储的值也不会变。