boost :: asio, потоки и синхронизация - PullRequest
10 голосов
/ 19 января 2011

Это в некоторой степени связано с этим вопросом , но я думаю, что мне нужно знать немного больше.Я пытался разобраться, как это сделать, в течение нескольких дней (работая над другими частями), но мне пришло время прикусить пулю и получить многопоточность.Кроме того, я хочу получить немного больше информации, чем связанный вопрос.

Во-первых, о многопоточности.Поскольку я тестировал свой код, я не беспокоился о многопоточности.Это просто консольное приложение, которое запускает соединение с тестовым сервером, и все остальное затем обрабатывается.Основной цикл таков:

while(true)
{
    Root::instance().performIO(); // calls io_service::runOne();
}

Когда я пишу свое основное приложение, я предполагаю, что это решение не будет приемлемым (так как оно должно быть вызвано в цикле сообщений, который, по возможности,возникли бы проблемы, когда очередь сообщений блокировала бы ожидание сообщения. Вы могли бы изменить это так, чтобы цикл сообщений не блокировался, но разве это не приведет к тому, что загрузка ЦП будет стремительно падать?)

Решение, которое кажется, состоит в том, чтобы бросить другую нить в это.В порядке Хорошо.Но потом я прочитал, что io_service::run() возвращается, когда нет работы.Что это такое?Это когда нет данных или нет соединений?Если хотя бы одно соединение существует, оно остается живым?Если это так, то это не такая большая проблема, поскольку мне нужно только запустить новый поток, когда установлено первое соединение, и я рад, если все это останавливается, когда ничего не происходит вообще.Я предполагаю, что меня смущает определение «ничего не делать».

Тогда мне нужно беспокоиться о синхронизации моего потока наддува с моим основным потоком GUI.Итак, я думаю, мои вопросы:

  1. Каков наилучший способ использования boost :: asio в клиентском приложении с точки зрения потоков и поддержания их в действии?
  2. Когдазапись в сокет из основного потока в поток ввода-вывода, выполняется ли синхронизация с использованием boost::asio::post, поэтому вызов в io_service происходит позже?
  3. Когда данные принимаются, как люди возвращают данные обратнопоток пользовательского интерфейса?В прошлом, когда я использовал порты завершения, я делал специальное событие, которое могло отправить данные обратно в основной поток пользовательского интерфейса, используя :: SendMessage.Это не было элегантно, но это сработало.

Сегодня я прочитаю еще кое-что, но было бы здорово узнать мнение кого-то, кто уже сделал это.Документация Boost :: asio невелика, и большая часть моей работы до сих пор основывалась на небольшой части документации, некоторых пробах / ошибках, некоторых примерах кода в Интернете.

Ответы [ 4 ]

6 голосов
/ 19 января 2011

1) Посмотрите на io_service :: work . Пока существует рабочий объект, io_service :: run не вернется. Поэтому, если вы начнете выполнять очистку, уничтожите рабочий объект, отмените все невыполненные операции, например async_read в сокете, дождитесь, пока run вернется и очистите ваши ресурсы.

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

3) Вам нужна какая-то система обмена сообщениями для информирования вашего потока GUI о новых данных. Здесь есть несколько возможностей.

Что касается вашего замечания о документировании, я считаю, что Asio - одна из лучших документированных библиотек наддува, и она имеет четкие примеры.

2 голосов
/ 20 января 2011

1) Каков наилучший способ использования boost :: asio в клиентском приложении с точки зрения потоков и их поддержки?

Как следует из документации , пул потоков, вызывающий io_service::run, является наиболее масштабируемым и простым в реализации.

2) При записи в сокет из основного потока в поток ввода-вывода выполняется синхронизация с использованиемboost :: asio :: post, чтобы вызов происходил позже в io_service?

Вам нужно будет использовать strand для защиты любых обработчиков, которые могут быть вызваны несколькимипотоки.См. этот ответ , поскольку он может вам помочь, а также этот пример.

3) Когда люди получают данные, как люди возвращают данные обратно в поток пользовательского интерфейса?В прошлом, когда я использовал порты завершения, я делал специальное событие, которое могло отправить данные обратно в основной поток пользовательского интерфейса, используя :: SendMessage.Это не было элегантно, но это работало.

Как насчет обеспечения обратного вызова в форме boost::function, когда вы отправляете асинхронное событие в io_service?Затем обработчик события может вызвать обратный вызов и обновить пользовательский интерфейс с результатами.

1 голос
/ 19 января 2011

boost::io_service::run() вернется только тогда, когда нечего делать, поэтому асинхронные операции не ожидают, например, асинхронное принятие / подключение, асинхронное чтение / запись или ожидание асинхронного таймера.поэтому перед вызовом io_service::run() сначала нужно запустить любую асинхронную операцию.

У меня нет, у вас есть консоль или приложение с графическим интерфейсом?в любом случае многопоточность выглядит излишним.вы можете использовать Asio вместе с вашей петлей сообщений.если это графический интерфейс win32, вы можете вызвать io_service :: run_one () из вашего обработчика OnIdle ().в случае консольного приложения вы можете настроить deadline_timer, который регулярно проверяет (каждые 200 мс?) ввод данных пользователем, и использовать его с io_service::run().все в одном потоке, чтобы значительно упростить решение

0 голосов
/ 20 января 2011

Когда данные получены, как люди возвращают данные в поток пользовательского интерфейса?В прошлом, когда я использовал порты завершения, я делал специальное событие, которое могло отправить данные обратно в основной поток пользовательского интерфейса, используя :: SendMessage.Это не было элегантно, но это работало

:: PostMessage может быть более подходящим.

Если все не выполняется в одном потоке, эти механизмы должны использоваться для безопасной публикации событий в потоке пользовательского интерфейса.

...