免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: yulihua49
打印 上一主题 下一主题

[C] 多线程服务器,发现个问题,请高人解惑 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2010-07-05 14:41 |只看该作者
回复 10# yulihua49


    虽然可能性很小,但是是存在的.这也解释了为什么你usleep以后情况会有所好转.最好的办法是在主线程里malloc一个Conn结构传给线程函数,然后在线程函数结束时free掉.另外,像这样的原形如果事先没有设置线程detach的话要在线程处理函数里加上pthread_detach(pthread_self());这么一句,要不然随着连接数的上升.会资源耗尽.

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
12 [报告]
发表于 2010-07-05 14:51 |只看该作者
本帖最后由 yulihua49 于 2010-07-05 14:54 编辑
Conn里的内容在创建线程的时候会被共用.比如你要创建两个线程,线程1里的Conn内容会被主线程改变.简单点说主 ...
samlumengjun 发表于 2010-07-05 13:45



   感谢哦,找到了。修改如下:
子线程:

  1. static void * thread_work(void *param)
  2. {
  3. T_Connect Conn=*(T_Connect *)param;
  4. T_NetHead Head;
  5. int ret,logined=0;
  6. T_SRV_Var ctx;
  7. srvfunc *fp;
  8. int svcnum=0;

  9. #ifdef __GNUC__
  10. char gda[Conn.SendLen+1];//本线程的全局数据区必须在此分配。
  11. #else
  12. char *gda=alloca(Conn.SendLen+1);
  13. #endif

  14.         if(Conn.SendLen>0) ctx.var=gda;
  15.         else ctx.var=0;
  16.         Conn.SendLen=0;
  17.         ctx.tid=pthread_self();//标志多线程服务
  18.         ctx.poolno=0;
  19.         ___SQL_Init_SQL_Connect(&ctx.SQL_Connect);
  20.         Conn.Var=&ctx;
  21.         Conn.only_do=0;
  22. //借用only_do存放函数地址 conn_init
  23.         if(((T_Connect *)param)->only_do) ((T_Connect *)param)->only_do(&Conn,&Head);
  24.         ((T_Connect *)param)->Socket=-1;//通知主线程,param可以重用了。
复制代码
主线程:
  1.   ret=pthread_create(&pthread_id,&attr,thread_work,&Conn);
  2.                 if(ret) {
  3.                         ShowLog(1,"%s:pthread_create:%s",__FUNCTION__,strerror(ret));
  4.                         close(s);
  5.                         if(ret==EAGAIN||ret==ENOMEM) {  //线程数用完了,休息一会,等一些线程退出
  6.                                 sleep(30);
  7.                         }
  8.                         continue;
  9.                 }
  10.                 while(Conn.Socket != -1) usleep(1000);//等子线程通知。
复制代码

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
13 [报告]
发表于 2010-07-05 15:11 |只看该作者
当然乱了,

s=accept(sock,(struct sockaddr *)&cin,&leng);

这个s都是每个线程公用的

                Conn.Socket=s;

                Conn.only_do=conn_init; //借用一下

                Conn.SendLen=sizeof_gda;

                ret=pthread_create(&pthread_id,&attr,thread_work,&Conn);、

可以改为

              int fd=s;

                Conn.Socket=fd;


                Conn.only_do=conn_init; //借用一下

                Conn.SendLen=sizeof_gda;

                ret=pthread_create(&pthread_id,&attr,thread_work,&Conn);、

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
14 [报告]
发表于 2010-07-05 15:29 |只看该作者
本帖最后由 yulihua49 于 2010-07-05 15:34 编辑
当然乱了,

s=accept(sock,(struct sockaddr *)&cin,&leng);

这个s都是每个线程公用的

           ...
chenzhanyiczy 发表于 2010-07-05 15:11



  谢谢,如上贴,每个线程用完了Conn,通知主线程,主线程收到通知再进行下一轮accept,就没问题了。
关键不是s共用,而是Conn共用了。s放到Conn里边跟你放到fd里边是一个意思。
s这个地址不会交给子线程,所以没必要fd,只是把s的值放到Conn,而Conn的地址交到子线程,就出现问题了,这个地址里的内容在一个时间里只能由一个线程使用。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
15 [报告]
发表于 2010-07-05 15:41 |只看该作者
本帖最后由 yulihua49 于 2010-07-05 15:44 编辑
回复  yulihua49


    虽然可能性很小,但是是存在的.这也解释了为什么你usleep以后情况会有所好转.最好 ...
samlumengjun 发表于 2010-07-05 14:41



    感谢支持。当初用你这办法也可能不错,现在Conn的使用串行化了,每收到一个连接都得等等,也能解决问题。就是需要等等,你的办法可能不需要等。
注意我子线程函数,发通知的时候,服务还未开始,只进行了初始化。线程还是并行的,只接受连接串行了。

论坛徽章:
0
16 [报告]
发表于 2010-07-05 16:41 |只看该作者
传值 和 传址

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
17 [报告]
发表于 2010-07-05 17:08 |只看该作者
本帖最后由 yulihua49 于 2010-07-05 17:11 编辑
回复  yulihua49


    虽然可能性很小,但是是存在的.这也解释了为什么你usleep以后情况会有所好转.最好 ...
samlumengjun 发表于 2010-07-05 14:41



    又出现新问题:
大量客户端同时传送数据时,个别线程会出现:
1 thrsrv:8942 07/05 16:17'07 thread_work:tid=46914753890624,接收结束,status=84,Invalid or incomplete multibyte or wide character
此时服务器端关闭连接,退出线程。服务器出现内存泄漏(占用内存增加,服务器不会死掉),客户端进程死等。大约500个链接里出现3-5个。

每出现一个这样的错误就会挂住一个客户端进程。

客户端的状态是,成功连接,与服务器协商密钥完成,发出登录包,等回答。
服务器未收到登录包。84号错误返回。

论坛徽章:
0
18 [报告]
发表于 2010-07-05 18:28 |只看该作者
回复 17# yulihua49


    为什么不看清楚我的回复?都和你说了像这样的原形如果事先没有设置线程detach的话要在线程处理函数里加上pthread_detach(pthread_self());这么一句,要不然随着连接数的上升.会资源耗尽.

论坛徽章:
0
19 [报告]
发表于 2010-07-05 18:49 |只看该作者
另外你的情况应该有两个问题,第一个问题就是我说的你没有设置线程属性,自行释放资源.还有一个问题是在客户端上,server这里close socket的话,客户端那里read到-1,应该也自己close socket.你客户端代码是怎么处理的?

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
20 [报告]
发表于 2010-07-06 13:32 |只看该作者
本帖最后由 yulihua49 于 2010-07-06 13:33 编辑
回复  yulihua49


    为什么不看清楚我的回复?都和你说了像这样的原形如果事先没有设置线程detach的话 ...
samlumengjun 发表于 2010-07-05 18:28



    哦,对不住,关注点没在这。
程序的前半部分没给,现在补上:
  1.         ret= pthread_attr_init(&attr);
  2.         if(ret) {
  3.                 ShowLog(1,"can not init pthread attr %s",strerror(ret));
  4.                 return ;
  5.         }
  6. //设置分离线程
  7.         ret=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
  8.         if(ret) {
  9.                 ShowLog(1,"can't set pthread attr:%s",strerror(ret));
  10.                 return ;
  11.         }
  12. //设置线程堆栈保护区 256K
  13.         ret=pthread_attr_setguardsize(&attr,(size_t)(1024 * 256));

复制代码
create_thread用的这个attr。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP