2014-02-20 4 views
1

Это длинный вопрос. TL; DR: Я не знаю, как правильно разрабатывать программы, используя asio.Как упростить многопоточный дизайн с помощью asio?

Люди написали GUI-обертки для служебных программ CLI. Я пишу «прокси» для такой утилиты, которая передает команды, выпущенные графическим интерфейсом, на другую копию утилиты, запущенной на удаленном компьютере (через другой «прокси» на удаленном компьютере).

настоящее время я использую ASIO для сокета I/O, но я использую простой цикл в main() для выполнения блокировки чтения из stdin (асинхронный ввод/вывод не представляется возможным на stdin & друзей на Windows). Я попытался разделить все, используя простой механизм pub/sub. Абоненты сообщений запускаются в своих потоках и получают сообщения от std::deque через std::condition_variable. Я в настоящее время имеют следующие I/O связанных классов:

  • SocketServer: Работает на собственном потоке, создает asio::io_service, связывается с & прослушивает порт, и принимает удаленные соединения.
  • SocketClient: Создает asio::io_service, подключается к удаленному хосту. & предоставляет пароль.
  • SocketConnection: Получает от SocketServer или SocketClient. Аутентификация удаленного хоста (только для сервера), чтение из сокета и запись в сокет при приеме SocketOutputMessage (в отдельном потоке).
  • ConsoleWriter: Выполняется в собственной ветке, записывается в stdout после получения ConsoleOutputMessage.

Для меня главный недостаток этого дизайна в том, что есть слишком много потоков! SocketServer нуждается в собственном потоке из-за блокировки вызова asio::io_service::run(). Аналогично, ConsoleWriter находится в своем собственном потоке, чтобы гарантировать, что все записи в stdout происходят в одном потоке. Мне не нужен еще один поток для SocketConnection, но он нужен как следствие pub/sub. (Я хочу, чтобы сообщение всегда отправлялось на ))

Возможно, кто-нибудь предоставит мне предложения по оптимизации этой конструкции (и, надеюсь, уменьшите количество требуемых потоков)? С этой целью существуют ли какие-либо функции asio, о которых я должен знать? Пожалуйста, предоставьте пример кода и/или ссылки на соответствующие сайты или ответы SO, если сможете.

Cheers.

ответ

2

Я рекомендую вам создать два io_services, первый (который вы можете отправлять в потоке) должен использоваться для всей связи сокетов.) И второй (диспетчер по основному потоку) должен обрабатывать активность консоли.

Например:

main() 
{ 
    // Run the network service 
    std::thread service([]() { net_service.run(); }); 
    // Now run the console service 
    console_service.run(); 
} 

Для связи между двумя службами, используйте io_service::post() операцию. Это отправляет обработчик на данную службу io, которая выполняется в этом контексте. Например.

client_socket.async_read_some(_data, [](...) { 
    // Now you have the data and you want to print it.. 
    console_service.post([=]() { std::cout << "message " << _data << std::endl; }); 
}); 

Так что теперь, когда вы читаете что-то из , вы размещаете, что данные в службу консоли - обратите внимание, что это важно, чтобы либо копировать данные или если вы хотите, чтобы избежать копий, создать некоторую отдельную очередь, как вы имеют и просто используют механизм post() для уведомления другого io_service.

ПРИМЕЧАНИЕ: В другом ответе упоминается poll(), это заставит контекст вращаться, поскольку он немедленно вернется, если ничего не будет выполнено.

0

io_serivce.poll() только запускает текущие события, а затем возвращает, я вызываю его повторно, вместо того, чтобы иметь поток только для этого.

Вы могли бы избежать consolewriter на его собственный потоке, заблокировав вокруг пишущих частей, некоторой форма блокировки/мьютекс/spinnlock/...

Если вы используете async_read() вместо чтения() вы поставляете обратный вызов, который вызывается всякий раз, когда есть данные для чтения. Таким образом вы позволяете asio обрабатывать потоки, и вам не нужно беспокоиться об этом.

Смежные вопросы