Стандартный асинхронный подход здесь не срабатывает (обратные вызовы отправки могут блокировать другие обратные вызовы при ожидании отправки нового объекта)
Асинхронная модель должна работать нормально, и при правильном использованииопределенно будет лучше масштабироваться - он развалится только тогда, когда вы введете блокировку.Вместо того, чтобы отключить асинхронность, вот что я бы предложил:
Удалите условную переменную.Вам нужны две очереди: OUTPUT и WAITING.
Затем при обработке клиента:
- Если в очереди OUTPUT есть данные, отправьте их.
- Если нет,поместите его в очередь WAITING.
Нет необходимости выполнять следующий ввод-вывод из обработчика предыдущего.Здесь вместо блокировки условной переменной мы просто перенаправляем ее в очередь WAITING для последующей обработки.
И в коде OUTPUT-pushing:
- Если вОжидание, отправьте данные напрямую.
- Если нет, нажмите на очередь OUTPUT.
Вот некоторый псевдокод:
queue<packet> output;
queue<client> waiting;
void try_send(client c)
{
if(!output.empty())
{
// there is output waiting to be sent, send it.
packet p = output.pop();
c.async_send(p, on_send_finished);
}
else
{
// nothing available, go back to waiting.
waiting.push(c);
}
}
void on_send_finished(client c)
{
// send finished, try again if any more output has accumulated:
try_send(c);
}
void push_output(packet p)
{
output.push(p);
if(!waiting.empty())
{
// there is a client waiting to send, give it a try.
client c = waiting.pop();
try_send(c);
}
}
Это может всесделать это масштабируемым способом, используя один поток, но несколько потоков довольно легко с asio.Если вы собираетесь использовать несколько потоков, вы захотите ввести блокировку в логику, которая проверяет очереди.