一次多线程臭虫经验——异步日志c++化时

  做任务单用go实现了异步日志,计划c++化练练手。本以为分分钟搞定的事,结果debug到凌晨两点/(ㄒoㄒ)/~~

  第一版关键代码如下:

AsyncLog::AsyncLog(size_t bufSize, WriteLogFunc func)
    : _curBuf(new Buffer(bufSize))
    , _nextBuf(new Buffer(bufSize))
    , _writeLogFunc(func)
    , _thread([&]{ this->_WriteLoop(bufSize);})
    , _running(true)
{ ::InitializeConditionVariable(&_cond);
  _thread.detach();
} AsyncLog::~AsyncLog()
{
if (_running) Stop(); } void AsyncLog::Append(const void* data, size_t len) { cLock lock(_mutex); _curBuf->append(data, len); if (_curBuf->writableBytes() == 0) { _bufVec.push_back(_curBuf); //FIXME:new可能返回null,不过那会系统已经要跪了吧~ _nextBuf ? (_curBuf = std::move(_nextBuf)) : (_curBuf.reset(new Buffer)); ::WakeConditionVariable(&_cond); } } void AsyncLog::_WriteLoop(size_t bufSize) { BufferPtr spareBuf1(new Buffer(bufSize)); BufferPtr spareBuf2(new Buffer(bufSize)); BufferVec bufToWriteVec; bufToWriteVec.reserve(8); while (_running){ { cLock lock(_mutex); ::SleepConditionVariableCS(&_cond, &_mutex, INFINITE); bufToWriteVec.swap(_bufVec); bufToWriteVec.push_back(_curBuf); _curBuf = std::move(spareBuf1); if (_nextBuf == NULL) _nextBuf = std::move(spareBuf2); } _writeLogFunc(bufToWriteVec);
if (spareBuf1 == NULL){ spareBuf1 = bufToWriteVec[0]; spareBuf1->clear(); } if (spareBuf2 == NULL){ spareBuf2 = bufToWriteVec[1]; spareBuf2->clear(); } bufToWriteVec.clear(); } } void AsyncLog::Stop() { _running = false; ::WakeConditionVariable(&_cond); _thread.join(); //Notice:阻塞,等待子线程执行结束 }

  共有五处Bug哟~

  • 用std::thread做成员,初始化列表指定子线程启动函数,该函数访问资源时,可能都没初始化好(ctor中调度出去了)
  • Stop逻辑是后添加的,_running成员声明在了末尾,其初始化即位于_thread之后,可能_WriteLoop执行时_running仍为false
  • 构造函数中,习惯性调_thread.detach(),析构函数中又调了_thread.join()
  • 竞态:_WriteLoop中的耗时IO操作_writeLogFunc(bufToWriteVec),可能调度至前台线程,若其继续写入数据,且触发析构或Stop,那多写的数据不会记Log,因为下次loop时_running已是false
  • Lambda表达式,用的引用捕获,this指针尚可,bufSize可是局部栈变量,指不定啥时候被戳死 ( ☉_☉)≡☞o────

  

  光构造函数就占了三 (╯‵□′)╯,所以说c++的抽象数据结构,碰上多线程,作死哇。防范ctor、dtor中途调度到别的线程,是门专业技能——详细可参考陈硕的书《Linux多线程服务端编程》前两章(这书前四章干货爆表)

  后记:写个代码,把所有该犯的错犯了个遍也是够可以的( ▔___▔)y

转载于:https://www.cnblogs.com/3workman/p/5810827.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值