免费注册 查看新帖 |

Chinaunix

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

[C] epoll的几个操作函数是线程安全吗? 表示怀疑~ [复制链接]

论坛徽章:
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
11 [报告]
发表于 2011-07-22 11:23 |只看该作者
回复  yulihua49

1.如果相应事件过多,超出了wait线程数量,这时候每个线程都会去处理一个task,而这个task的处理事件过长,那么就没有线程在 epoll上等待,会造成网络处理的低效(比如连接拒绝)
ydfgic 发表于 2011-07-20 17:57


accept不在这里(在主线程里),所以无线程可用,不影响连接的接入。接入后的fd在epoll队列里等着。

论坛徽章:
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 [报告]
发表于 2011-07-22 11:25 |只看该作者
本帖最后由 yulihua49 于 2011-07-22 11:56 编辑
回复  yulihua49

只有一个线程在等待任务队列,如果同时到达几个任务的时候,就没有及时的线程相应去处理(当然,那些丢任务的线程会去取队列front端的任务,但是万一不及时呢?)
ydfgic 发表于 2011-07-20 17:57

经过大压力测试,不会发生这种情况。
rdy队列平时是空的,我们在此浪费了一个线程。
当有客户端请求时,一定会有一个follower先激活,激活后没有线程转换,直接进入工作。所以效率很高。
在工作中,如果需要连接池,他会直接申请,如果申请成功,直接工作,仍然没有线程切换。就是,rdy队列仍然无事可做。
只有申请失败,把任务排到相应的wait队列由另外的线程专门负责等待连接池。工作线程释放,回到follower。
weit线程得到连接后,交给该任务,把它排到rdy队列。这就激活了leader.
这都是连接池耗尽才有的动作。此时一定会有大量work线程在活动。活动结束的线程通常会在第一时间抓取rdy,甚至连leader都不做,直接进入下一个work。那些得到连接池的任务,万事俱备,以最高的优先级迅速得到服务,以便尽快释放连接池。
测试表明这是一个效率极高的方案。
一个交易转发器,
在16核,20个线程。每秒转发,62200个交易。CPU使用率高达1485%。负载是均衡的。最忙线程是不断变换的,所有线程都繁忙,并没有当leader上瘾不干活的。

同时到达上万的任务,该在哪等就在哪,总会得到服务,不会饿死的。

epoll_wait是竞争安全的,所以没必要L/F。

论坛徽章:
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
13 [报告]
发表于 2011-07-22 12:02 |只看该作者
本帖最后由 yulihua49 于 2011-07-22 12:06 编辑
回复  yulihua49

我想至少要有个线程保证在处理网络输入,而不是自己去做事,应该丢到 任务队列里,排队去。或者靠优先级,让高优先级的直接处理,长时间的丢队列。
其实这样我觉得和HS/HA半同步/半异步模式 差不多了,这个可能更高效点,在线程资源的使用上。ydfgic 发表于 2011-07-20 17:57

的确如此。看看主线程片断:
  1.         while(1) {
  2.                 do {
  3.                         FD_ZERO(&efds);
  4.                         FD_SET(sock, &efds);
  5. //健康检查周期
  6.                         tm.tv_sec=30;
  7.                         tm.tv_usec=0;
  8.                         ret=select(sock+1,&efds,NULL,&efds,&tm);
  9.                         if(ret==-1) {
  10.                                 ShowLog(1,"select error %s",strerror(errno));
  11.                                 close(sock);
  12.                                 quit(3);
  13.                         }
  14.                         if(ret==0) {
  15.                                 check_TCB_timeout();
  16.                                 if(poolchk) poolchk();
  17.                         }
  18.                 } while(ret<=0);
  19.                 i=event_no();
  20.                 s=accept(sock,(struct sockaddr *)&cin,&leng);
  21.                 if(s<0) {
  22.                         ShowLog(1,"%s:accept err=%d,%s",__FUNCTION__,errno,strerror(errno));
  23.                         switch(errno) {
  24.                         case EMFILE:    //fd用完了,其他线程还要继续工作,主线程休息一下。
  25.                         case ENFILE:
  26.                                 sleep(30);
  27.                                 continue;
  28.                         default:break;
  29.                         }
  30.                         sleep(15);
  31.                         if(++repeat < 20) continue;
  32.                         ShowLog(1,"%s:network fail! err=%s",__FUNCTION__,strerror(errno));
  33.                         close(sock);
  34.                         quit(5);
  35.                 }
  36.                 repeat=0;
  37.                 task=&client_q.pool[i];
  38.                 client_q.pool[i].fd=s;
  39.                 task->conn.Socket=s;
  40.                 task->conn.timeout=120;
  41.                 task->status=-1;
  42.                 task->conn.only_do=(int (*)())conn_init;
  43.                 ret=do_epoll(task,EPOLL_CTL_ADD);//任务交到epoll队列。
  44.         }
复制代码

论坛徽章:
0
14 [报告]
发表于 2011-08-28 10:00 |只看该作者
本帖最后由 dreamyseason 于 2011-08-28 10:02 编辑

主线程压入连接任务,工作线程取出任务同时处理网络事件,难道没有压入非连接任务的线程?这样的话相当于没有普通(非连接请求)数据包的缓冲,任务队列的作用大打折扣。

论坛徽章:
8
申猴
日期:2014-01-01 22:11:07白羊座
日期:2014-11-18 20:53:022015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之四川
日期:2016-01-19 18:39:36综合交流区版块每日发帖之星
日期:2016-06-07 06:20:0015-16赛季CBA联赛之广东
日期:2016-10-30 11:34:40CU十四周年纪念徽章
日期:2016-11-13 10:06:5715-16赛季CBA联赛之同曦
日期:2022-08-28 15:58:19
15 [报告]
发表于 2011-08-28 14:28 |只看该作者

论坛徽章:
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
16 [报告]
发表于 2011-08-29 13:58 |只看该作者
主线程压入连接任务,工作线程取出任务同时处理网络事件,难道没有压入非连接任务的线程?这样的话相当于没 ...
dreamyseason 发表于 2011-08-28 10:00



    没听明白

论坛徽章:
0
17 [报告]
发表于 2011-08-29 16:46 |只看该作者
从你提供的代码来看,只向任务队列里压入新连接的任务,而没有压入其它监听到的事件,比如收到一个业务数据包。

论坛徽章:
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
18 [报告]
发表于 2011-08-30 16:28 |只看该作者
本帖最后由 yulihua49 于 2011-08-30 16:53 编辑
从你提供的代码来看,只向任务队列里压入新连接的任务,而没有压入其它监听到的事件,比如收到一个业务数据 ...
dreamyseason 发表于 2011-08-29 16:46



   哦,压入了。在do_work()里,没贴出来。
它是在完成或夭折一个任务后,判决,如何ctl,EPOLL_CTL_MOD,EPOLL_CTL_DEL,也许会弄另一个相关的fd。这完全取决于处理逻辑,没有通用性,所以没贴出来。

我前边两段是通用的,你自己稍改一下就行。do_work()你自己写,干啥都行,最后得给epoll一个交待。

我这里是这样的:
  1. //工作线程 LT方式
  2. static int do_work(TCB *task)
  3. {
  4. int ret,cc;
  5. T_Connect *conn;
  6. void (*init)(T_Connect *,T_NetHead *);
  7. T_SRV_Var *ctx=&task->sv;
  8. 。。。。。。。。。。。。。。。。。。
  9. //            ret=do_some_thing(,,,);
  10.           switch(ret) {
  11.                 case -1:
  12.                         cc=do_epoll(task,EPOLL_CTL_DEL);
  13.                         client_del(task);
  14.                         ShowLog(2,"%s: disconnect by server",__FUNCTION__);
  15.                 case -5://epoll人家都处理好了,不用你管。
  16.                         break;
  17.                 default:
  18.                         cc=do_epoll(task,EPOLL_CTL_MOD);
  19.                         if(cc && errno != EEXIST) {
  20.                                 ShowLog(1,"%s:cancel by server",__FUNCTION__);
  21.                                 client_del(task);
  22.                         }
  23.                         break;
  24.                 }
  25.                 mthr_showid_del(ctx->tid);
  26.                 return 0;
  27. }
复制代码
都是成熟的,非常可靠的框架啦,应用中的。

论坛徽章:
0
19 [报告]
发表于 2011-08-31 12:45 |只看该作者
epoll一定加了EPOLLONESHOT标志了吧,否则处理任务的线程就会冲突了。
      另外可以考虑用一个线程监听并压入任务队列,另外几个工作线程直接处理对时序没有要求的客户请求而不压入队列,如果这样的操作很多的话应该是合算的。

论坛徽章:
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 [报告]
发表于 2011-08-31 13:58 |只看该作者
epoll一定加了EPOLLONESHOT标志了吧,否则处理任务的线程就会冲突了。
     
dreamyseason 发表于 2011-08-31 12:45



    完全正确!do_epoll()里干的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP