сбой boost :: async_write после записи в течение некоторого времени - PullRequest
1 голос
/ 26 мая 2011

У меня очень специфическая проблема. Я написал сервер, который записывает данные, которые он получает от третьей стороны для подключенных клиентов. Сервер пишет клиенту (-ам) нормально некоторое время, но через некоторое время async_write либо завершается ошибкой, либо запись никогда не возвращается. Для моей программы, если async_write никогда не возвращается, то никакие последующие записи не будут выполняться, и мой сервер будет помещать в очередь данные, полученные от третьей стороны, пока все не взорвется.

Я включил свой код ниже:

void ClientPartitionServer::HandleSignal(const CommonSessionMessage& message, int transferSize) {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  if(m_clientSockets.size() != 0) {
    TransferToQueueBuffer(message.GetData(), transferSize);
  }
  if(m_writeCompleteFlag) {
    // TransferToWriteBuffer();
    for(vector<boost::asio::ip::tcp::socket*>::const_iterator i = m_clientSockets.begin(); i != m_clientSockets.end(); ++i) {
      WriteToClient(*i);
    }
  }
}

void ClientPartitionServer::WriteToClient(boost::asio::ip::tcp::socket* clientSocket) {
  m_writeCompleteFlag = false;
  cout << "Iniating write: " << m_identifier << endl;
  boost::asio::async_write(
    *clientSocket,
    boost::asio::buffer(m_queueBuffer.get(), m_queueBufferSize),
    boost::bind(
      &ClientPartitionServer::HandleWrite, this,
      boost::asio::placeholders::error,
      boost::asio::placeholders::bytes_transferred
  ));
}

void ClientPartitionServer::HandleWrite(const boost::system::error_code& ec, size_t bytes_transferred) {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  if(ec != 0) {
    cerr << "Error writing to client: " << ec.message() << " " << m_identifier << endl;
    // return;
    cout << "HandleWrite Error" << endl;
    exit(0);
  }
  cout << "Write complete: " << m_identifier << endl;
  m_writeCompleteFlag = true;
  m_queueBuffer.reset();
  m_queueBufferSize = 0;
}

Любая помощь будет оценена.

Спасибо.

Ответы [ 3 ]

4 голосов
/ 27 мая 2011

Не видя весь код, трудно сказать, но для меня это красный флаг, что вы держите мьютекс при множественных (или даже при одном) WriteToClient вызовах. Обычно удержание блокировки ввода-вывода любого типа (даже асинхронной, как у вас здесь) в лучшем случае ухудшает производительность, а в худшем - рецепт странных тупиковых ситуаций под нагрузкой. Что произойдет, если асинхронная запись завершится inline и вам перезвонят, например, на HandleWrite в том же потоке / callstack?

Я бы попытался изменить это так, чтобы блокировка снималась во время вызовов записи.

Каким бы ни было решение, более общий совет:

  • не блокировать ввод / вывод
  • добавить диагностический вывод - что поток вызывает каждый обработчик, и в какой заказ?
  • попробуйте отладку, как только вы нажмете состояние покоя. Должен иметь возможность диагностировать тупик от
    состояние процесса.
1 голос
/ 28 мая 2011

Использование нитей для сериализации доступа к определенным объектам соединения. В частности, проверьте strand :: wrap () . Чтобы увидеть другие примеры использования цепей, посмотрите несколько разных примеров таймера (хотя код работает для любого async_*() вызова).

0 голосов
/ 14 марта 2013

Прежде всего, я не согласен с комментариями, указывающими на то, что удержание блокировок в асинхронной операции является проблемой.

Сохранение блокировок на:

  1. Любойфункция, которая вызывает обратные вызовы, является плохой.

  2. Любая операция блокировки является плохой.

async_write явно не гарантирует ни блокирование, ни вызов обработчика, так что мне приятно держать блокировку.

Однако я вижу ошибку в вашем коде, которая нарушает другое требование async_write.Вы не можете вызывать async_write, пока не будет вызван обработчик завершения.Это то, что вы нарушаете.

m_writeCompleteFlag устанавливается на true всякий раз, когда вызывается один из обработчиков .Это означает, что вы можете нарушать правила async_write для некоторых других разъемов N-1 при высокой нагрузке.

...