ascs 简明开发教程(九):注意事项

31 篇文章 0 订阅
31 篇文章 1 订阅

QQ交流群:198941541

1. 什么是service线程?

它是ascs库使用的工作线程,个数由service_pump::start_service(int)指定,默认8个。可以运行时增加,调用service_pump::add_service_thread(int)即可,如果你想运行时减少,则需要定义宏ASCS_DECREASE_THREAD_AT_RUNTIME,然后调用service_pump::del_service_thread(int),可以最多减少到只剩下1个,注意这个功能会稍微影响一点点效率。

2. 所有回调函数都在service线程里面被调用,所以注意与你的线程互斥(如果需要的话)。如果你需要阻塞service线程,就需要小心了,注意别死锁了;其次就是尽量减少阻塞时间,因为service线程往往远远少于你的连接总数量,阻塞一个线程就少一个线程,会间接的影响所有其它连接,如果阻塞的连接数量等于service线程总数,则其它连接即便没有阻塞,也是得不到调度的机会的。如果你的业务很耗时,你可以另开工作线程来处理业务,或者增加service线程的数量。

3. 不得因为等待发送缓存可用而阻塞在service线程,这样可能会发生死锁。比如你在on_msg_handle里面把消息返回回去,但调用send_msg失败,于是你换成safe_send_msg以保证成功(且最简单),但因为safe_send_msg是阻塞的,且原因刚好是等待发送缓存可用,那么死锁是怎么发生的呢?比如你开了8个service线程,然后有8条连接阻塞在on_msg_handle里面的safe_send_msg上面,此时已经没有service线程可用于任何连接上的数据的读取了。safe_send_msg返回的条件是对方接收一些数据,让己方发送缓存变得可用,可是对方有可能处于相同的状态,即8条连接阻塞在on_msg_handle里面的safe_send_msg上面,对方也没有service线程可用于任何连接上的数据的读取了,死锁就这样发生了。

4. send_msg时,can_overflow有什么用意?

每个ascs socket都有发送和接收缓存(同步派发消息时可以不用接收缓存,前面说过了),所以在缓存没满的情况下,即便连接没有建立起来,你仍然可以成功的发送消息(所以这里的成功和send API成功一样,只表示消息已经成功到达ascs,并不表示消息到了对方且被对方接收),缓存的大小可通过宏ASCS_MAX_SEND_BUF和ASCS_MAX_RECV_BUF,或者send_buf_size和recv_buf_size接口控制。can_overflow的意思是不考虑缓存满不满的问题,所以消息发送总是能成功,但这是有风险的,如果发送方比接收方快,那么发送方堆积的消息会越来越多,直到内存耗尽。那么can_overflow还敢用吗?还有意义吗?答案是肯定的,当你确信某种消息不会无限地发送时,就可以用,比如收到消息A时,判断发送缓存未满,于是处理它并产生了BCD三个回应消息,这三个消息中的后两个会造成缓存满,此时可以以can_overflow调用send_msg,因为溢出数量是可控的(最多两条消息),下次再收到A时,又要先判断发送缓存的可用情况(不可用时可以拥塞控制,后面会讲到),溢出的数量仍然可控。再有一点,这种情况下你想精确控制缓存不满还真有难度,吃力不讨好。

5. 如果开启了断线自动重连,那么重连之后,发送缓存不会被清空,如果你需要可在on_connect里面调用clear_buffer()函数;对于接收缓存,ascs总是会派发完所有已经接收到的消息,即便是连接已经断了。

6. 接收缓存的控制由ascs进行,当接收缓存满之后,会暂停消息接收,暂停时间可以通过宏ASCS_MSG_RESUMING_INTERVAL和msg_resuming_interval接口控制。

7. 拥塞控制

发送拥塞控制由用户自己做,比如send_msg失败之后暂停一段时间再send_msg,或者调用safe_send_msg(注意在你自己的线程里面调,前面说了,不得在service线程里面调);接收拥塞控制可以通过被动接收的方式(以后会有详解),或者当接收缓存满时由ascs自动控制(前面第6条),或者在异步派发回调函数里面返回0或者false(表示没有处理消息),那么消息将暂停一段时间再派发,暂停时间由宏ASCS_MSG_HANDLING_INTERVAL和msg_handling_interval接口控制;注意同步派发无法做拥塞控制(但可以适当地在on_msg里面阻塞一小段时间,只是注意阻塞会间接影响其它所有连接,前面我们说过了)。

8. 线程安全

不同socket之间所有的回调都是并发的,对于同一个socket,on_msg之间是顺序的,on_msg_handle之间也是顺序的,on_msg和on_msg_handle是并发的(前面说了,on_msg没处理完的消息,会继续异步派发,结果消息会乱序),其它所有回调之间都是并发,除非有明显先后顺序的,比如on_connect肯定在on_recv_error之前。

对于socket的线程安全性,不同的socket之间显然是安全的(因为socket之间不共享任何数据,比如全局数据什么的),对于同一个socket,也几乎都是线程安全的(比如你可以多线程调用send_msg),除了:1。操作同一个定时器;2。关闭连接。

9. 状态管理及资源释放

调用on_connect之时,连接建立;调用on_recv_error之时,连接断开;如果你有资源需要释放(你只释放你自己创建的对象,socket自己不是你直接创建的,不需要你来释放),则应该在on_close里面做。如果你开启了对象重用(定义了宏ASCS_REUSE_OBJECT或者ASCS_RESTORE_OBJECT,以后会有详解),则你需要重写reset函数并在里面重置所有你自己的数据,否则当socket被重用之后(此时已经是另一条连接了)还会保有之前的脏数据。

10. 不得想当然地认为on_msg_handle一定会在on_recv_error之前,有可能on_recv_error之后,还会有消息未派发完(前面第5条)。但on_close一定在after_close之前,且它俩一定是最后被调用的。

11. 凡是你送给ascs的消息,之后你都不用再维护其有效性,ascs会根据你传入的参数是否是右值引用而决定是将消息swap到自己的缓存还是拷贝(这里说的拷贝并不是绝对的内存拷贝,只是执行拷贝赋值函数而已,如果你的消息是shared_buffer,那不会有真正的拷贝,只是引用计数加1而已)到自己的缓存(这一点与st_asio_wrapper有点区别,st库对于非const引用,就会把消息swap到自己的缓存,因为st库只需要c++98标准,它还不支持右值引用),这些消息包括packer返回的消息,调用direct_(sync_)send_msg传入的消息等;凡是ascs送给你的消息,都是非const引用,这意味着你可以将其swap到自己的缓存(如果你需要保存的话),ascs不会再使用它们,这些消息包括从on_(all_)msg_send,on_msg,on_msg_handle传出的消息,同步读取返回的消息等。

上一篇:ascs 简明开发教程(8)下一篇:ascs 简明开发教程(10)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值