97资源超碰:解锁数字娱乐新维度,探索无限可能

核心内容摘要

校园时光掠影:那一次“班花趴下让我”的奇妙课间
鸣神遗落的红白羽衣:荒野中的原始契约与生命回响

78入13:数字里的生命密码,洞悉命运的奇妙轨迹

在编写多线程并发服务器(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局部变量变了,数组中存储的值也不会变。

代码实战下面是一个完整的、可运行的多线程并发服务器代码案例。

代码实现 (server_fixed.c)#includestdio.h#includestdlib.h#includeunistd.h#includestring.h#includearpa/inet.h#includepthread.h#includectype.h#defineMAX_CONN1024#definePORT8888// 定义一个结构体来存储每个连接的信息structSockInfo{intfd;// 通信文件描述符structsockaddr_inaddr;// 客户端地址信息(可选,方便日志打印)};// 全局数组,用于管理所有连接// 初始化时需要将fd设为-1,表示空闲structSockInfoinfos[MAX_CONN];// 子线程的工作函数void*worker(void*arg){//

将参数强转回结构体指针structSockInfo*pinfo=(structSockInfo*)arg

日皮-日皮应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123