ZLMediaKit/ZLToolKit

Socket::flushData function, multi-threaded data sending order issue

csenjoy opened this issue · 3 comments

获取待发送send_buf_sending_tmp

decltype(_send_buf_sending) send_buf_sending_tmp;
    {
        // 转移出二级缓存
        LOCK_GUARD(_mtx_send_buf_sending);
        if (!_send_buf_sending.empty()) {
            send_buf_sending_tmp.swap(_send_buf_sending);
        }
    }

发送逻辑

      while (!send_buf_sending_tmp.empty()) {
          auto &packet = send_buf_sending_tmp.front();
          auto n = packet->send(sock, _sock_flags);
         ......
      }

多线程环境下(例如,用户调用send触发的flushData和EventPoller触发的flushData)都能获取一个send_buf_sending_tmp发送。
这种情况下,可能会存在后添加的Buffer::Ptr被先发送的情况。


//socket可写,则调用flushData写数据到socket
    if (_sendable) {
        return flushData(sock_fd_->rawFd(), sock_fd_->type(), false);
    }

Socket注册写事件的时候,_sendable被设置为false了,并不会造成多线程访问flushData

_sendable作为限制用户调用flushData时,默认情况应该是false。因为默认情况下Socket会注册写事件回调

    //标记该socket是否可写,socket写缓存满了就不可写
    std::atomic<bool> _sendable {true};

修改为

    //标记该socket是否可写,socket写缓存满了就不可写
    std::atomic<bool> _sendable {false};

嗨 Socket不是线程安全的 现在在zlmediakit中所有的socket操作都能保证在其归属poller线程执行了
但是由于历史原因 并没有在Socket中做线程检查等限制工作

建议先poller->async 然后再执行Socket的send函数