ZLMediaKit / ZLToolKit

一个基于C++11的轻量级网络框架,基于线程池技术可以实现大并发网络IO
MIT License
1.94k stars 581 forks source link

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

Closed csenjoy closed 11 months ago

csenjoy commented 11 months ago

Get the send_buf_sending_tmp to be sent

 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);
          }
      }

Sending Logic

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

In a multi-threaded environment (for example, flushData triggered by user calling send and flushData triggered by EventPoller), a send_buf_sending_tmp can be obtained for sending. In this case, it is possible that the Buffer::Ptr added later will be sent first.

获取待发送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被先发送的情况。

TRANS_BY_GITHUB_AI_ASSISTANT

csenjoy commented 11 months ago

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

When the socket registers a write event, _sendable is set to false, which will not cause multi-threaded access to flushData.

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


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

`TRANS_BY_GITHUB_AI_ASSISTANT`
csenjoy commented 11 months ago

_sendable should be false by default when limiting users from calling flushData. This is because the Socket will register a write event callback by default.

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

Modified to

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

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

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

修改为

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

TRANS_BY_GITHUB_AI_ASSISTANT

xia-chu commented 11 months ago

Hi, Socket is not thread-safe. Now in zlmediakit, all socket operations are guaranteed to be executed in their belonging poller thread. However, due to historical reasons, no thread checking or other restrictions have been implemented in Socket.

It is recommended to first poller->async and then execute the Socket's send function.

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

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

TRANS_BY_GITHUB_AI_ASSISTANT