回调函数 线程_从0实现基于Linux socket聊天室-多线程服务器一个很隐晦的错误-2...
根据 《0 基于socket和pthread实现多线程服务器模型》所述,server创建子线程的时候用的是以下代码:
pconnsocke = (int *) malloc(sizeof(int));*pconnsocke = new_fd;ret = pthread_create(&tid, NULL, rec_func, (void *) pconnsocke);if (ret
为什么必须要malloc一块内存专门存放这个新的套接字呢?
要讲清楚这个问题的原因需要一些背景知识:
Linux创建一个新进程时,新进程会创建一个主线程;
每个用户进程有自己的地址空间,系统为每个用户进程创建一个task_struct来描述该进程,实际上task_struct 和地址空间映射表一起用来,表示一个进程;
Linux里同样用task_struct来描述一个线程,线程和进程都参与统一的调度;
进程内的不同线程执行是同一程序的不同部分,各个线程并行执行,受操作系统异步调度;
由于进程的地址空间是私有的,因此在进程间上下文切换时,系统开销比较大;
在同一个进程中创建的线程共享该进程的地址空间。
明白这些基础知识后,下面我来看下,当进程创建一个子线程的时候,传递的参数情况:
直接传递栈中内存地址
我们首先分析下如果创建子线程传递的是局部变量new_fd的地址这种情况。
由上图所示:
创建一个线程,如果我们按照图中传递参数方法,那么new_fd是在栈中的,创建子线程的时候我们把new_fd地址传递给了thread1,线程回调参数arg的地址是new_fd地址。
因为主函数会一直循环不退出,所以new_fd一直存在栈中。用这种方法的确可以把new_fd的值3传递到子线程的局部变量fd,这样子线程就可以使用这个fd与客户端通信。
但是因为我们设计的是并发服务器模型,我们没有办法预测客户端什么时候会连接我们的服务器,假设遇到一个极端情况,在同一时刻,多个客户端同时连接服务器,那么主线程是要同时创建多个子线程的。
多个客户端同时连接服务器
如上图所示,所有新建的的thread回调函数的参数arg存放的都是new_fd的地址。如果客户端连接的时候时间间隔比较大,是没有问题的,但是在一些极端的情况下还是有可能出现由于高并发引起的错误。
我们来捋一下极端的调用时序:
如上图所示:
T1时刻,当客户端1连接服务器的时候,服务器的accept函数会创建新的套接字4;
T2时刻,创建了子线程thread1,同时子线程回调函数参数arg指向了栈中new_fd对应的内存。
假设,正在此时,又有一个客户端要连接服务器,而且thread1页已经用尽了时间片,那么主线程server会被调度到。
如上图所示:
T3时刻,主线程server接受了客户端的连接,accept函数会创建新的套接字5,同时创建子线程thread2,此时OS调度的thread2;
T4时刻,thread2通过arg得到new_fd了的值5,并存入fd;
T5时刻,时间片到了,调度thread1,thread1通过arg去读取new_fd,此时栈中new_fd的值已经修5覆盖了;
所以出现了2个线程同时使用同一个fd的情况发生。
这种情况的发生,虽然概率很低,但是并不代表不发生,该bug就是一口君在解决实际项目中遇到过的。
传递堆内存地址
如果采用传递堆的地址的方式,我们看下图:
T1时刻,当客户端1连接服务器的时候,服务器的accept函数会创建新的套接字4,在堆中申请一块内存,用指针pconnsocke指向该内存,同时将4保存到堆中;
T2时刻,创建了子线程thread1,同时子线程回调函数参数arg指向了堆中pconnsocke指向的内存。
假设,正在此时,又有一个客户端要连接服务器,而且thread1页已经用尽了时间片,那么主线程server会被调度到。
T3时刻,主线程server接受了客户端的连接,accept函数会创建新的套接字5,在堆中申请一块内存,用指针pconnsocke指向该内存,同时将5保存到堆中,然后创建子线程thread2;
T4时刻,thread2通过arg指向了堆中pconnsocke指向的内存,此处值为5,并存入fd;
T5时刻,时间片到了,调度thread1,thread1通过arg去读取fd,此时堆中数据位5;
就不会出现了2个线程同时使用同一个fd的情况发生。
这个知识点有点隐蔽,希望读者在使用的时候多加小心。下一章,我们要讲解如何利用我们现有的代码实现登录注册的功能。
获取更多关于Linux的资料,请关注公众号「一口Linux」
回调函数 线程_从0实现基于Linux socket聊天室-多线程服务器一个很隐晦的错误-2...相关推荐
- linux下多进程聊天室,从0实现基于Linux socket聊天室-多线程服务器模型-1
前言 Socket在实际系统程序开发张中,应用非常广泛,也非常重要.实际应用中服务器经常需要支持多个客户端连接,实现高并发服务器模型显得尤为重要.高并发服务器从简单的循环服务器模型处理少量网络并发请求 ...
- 从0实现基于Linux socket聊天室-实现聊天室的公聊、私聊功能-4
前面文章链接如下: <从0实现基于Linux socket聊天室-多线程服务器模型-1> <从0实现基于Linux socket聊天室-多线程服务器一个很隐晦的错误-2> &l ...
- 基于linux网络聊天室的设计,参考基于linux网络聊天室的设计.doc
参考基于linux网络聊天室的设计 长沙理工大学<高级操作系统>课程设计报告学 院 计算机与通信工程 专 业 计算机科学与技术 班 级 学 号 学生姓名 指导教师 课程成绩 完成日期 课程 ...
- 基于C#的socket聊天室(附源码)
基于C#-socket聊天室 前言 源代码:https://gitee.com/TL0902/term/blob/master/C%23%E8%81%8A%E5%A4%A9%E5%AE%A4/Tcha ...
- 基于WebSocket实现聊天室(Node)
基于WebSocket实现聊天室(Node) WebSocket是基于TCP的长连接通信协议,服务端可以主动向前端传递数据,相比比AJAX轮询服务器,WebSocket采用监听的方式,减轻了服务器压力 ...
- 基于阿里云用C/C++做了一个http协议与TCP协议的web聊天室的服务器——《干饭聊天室》
基于阿里云用C/C++做了一个http协议与TCP协议的web聊天室的服务器--<干饭聊天室> 在这里首先感谢前端小伙伴飞鸟 前端技术请看一款基于React.C++,使用TCP/HTTP协 ...
- 基于Python的聊天室
基于Python的聊天室 文章目录 基于Python的聊天室 一.引言 1.1 背景和意义 1.2 系统要实现的功能 1.2.1 用户登录 1.2.2 群发消息 1.2.3 一对一聊天 1.2.4 发 ...
- SSM(五)基于webSocket的聊天室
SSM(五)基于webSocket的聊天室 前言 不知大家在平时的需求中有没有遇到需要实时处理信息的情况,如站内信,订阅,聊天之类的.在这之前我们通常想到的方法一般都是采用轮训的方式每隔一定的时间向服 ...
- 用Asp.Net创建基于Ajax的聊天室程序
原作者Dahan Abdo 译自CodeProject 如要下载源代码,请到我的网站,地址:http://www.vczx.com/article/show.php?id=1796 简 介 我的第一个 ...
最新文章
- windows平台下vlc编译之六:vlc-0.9.8a的编译
- ElasticSearch入门系列(三)文档,索引,搜索和聚合
- double 格式化
- 基于java的数据结构学习——数组实现的栈以及简单应用C++实现
- vue2.0 路由不显示router-view
- WeChat.app debuger
- 如何在Java客户端调用RESTful服务
- centos下配置LNMP环境(源码安装)
- MySQL如何按天统计数据,没有记录的天自动补充0
- 信息安全之程序实现简单替换加密,并用字母频率统计进行破解
- java jdbc 参数 转义_jdbc URL中的各个参数详解
- ofd文件的查看、打印、下载、上传
- 机器视觉:光源基础及选型
- C语言面试部分知识点整理总结
- 设置全局键盘钩子和消息钩子
- 病毒手动查杀(威金 q盗 熊猫烧香)
- 快速学习探索性测试,什么是探索性测试?
- rovio视觉里程计的笔记
- 【USACO3-4-2】电网 皮克定理
- 滴滴自动驾驶服务上线,程维:道阻且长,行则将至