boost :: asio :: io_service, std :: thread, не может понять результат кода - PullRequest
0 голосов
/ 23 марта 2020

Я изучаю библиотеку boost :: asio для написания UDP-клиента и сервера, и, к сожалению, я не имею представления о результатах этого кода:

#include <boost/asio.hpp>
#include <thread>
#include <mutex>
#include <chrono>
#include <iostream>

int main() {
    boost::asio::io_service service;
    std::mutex mtx;

    for (int i = 0; i < 20; ++i)
    {
        service.post([i, &mtx]() {
            std::scoped_lock<std::mutex> lg(mtx);
            std::cout << '[' << std::this_thread::get_id()
                      << "] " << " Handler [" << i << "]" << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        });
    }

    std::vector<std::thread> pool;

    for(int i = 0; i < 4; i++)
        pool.emplace_back([&service]() { service.run(); });

    for (auto& thread : pool)
        if (thread.joinable())
            thread.join();
}

Он отправляет двадцать обработчиков в al oop, где каждый печатает его идентификатор и затем спит секунду. Для запуска я создаю вектор, где каждый элемент запускает io_service. Результат этого кода:

[139801306236672]  Handler [0]
[139801306236672]  Handler [4]
[139801306236672]  Handler [5]
[139801306236672]  Handler [6]
[139801306236672]  Handler [7]
[139801306236672]  Handler [8]
[139801306236672]  Handler [9]
[139801306236672]  Handler [10]
[139801306236672]  Handler [11]
[139801306236672]  Handler [12]
[139801306236672]  Handler [13]
[139801306236672]  Handler [14]
[139801306236672]  Handler [15]
[139801306236672]  Handler [16]
[139801306236672]  Handler [17]
[139801306236672]  Handler [18]
[139801306236672]  Handler [19]
[139801185482496]  Handler [2]
[139801297843968]  Handler [3]
[139801289451264]  Handler [1]

Я понятия не имею, почему обработчики, проиндексированные с 1, 2 и 3, заканчиваются как 2 - 3 - 1. Я попробовал также dispatch () вместо post () метод и результат тот же. Может кто-нибудь объяснить, что здесь происходит?

Ответы [ 2 ]

1 голос
/ 23 марта 2020

Согласно документации asio, асинхронные обработчики завершения будут вызываться только из потоков, которые в данный момент вызывают service.run(). Вы звоните service.run() из нескольких тем. Каждый вызов отменяет обработчик и вызывает его. Потоки планируются ОС, и так получилось, что поток, который снял с обработки обработчик i=2, был запланирован раньше, чем поток, который снял с обработки обработчик i=1.

Ваш код не накладывает никакого порядка на выполнение обработчиков, как есть. Если вы хотите последовательный вызов обработчиков, просто вызовите service.run() один раз. В более сложном сценарии вы можете использовать цепочки asio для последовательного вызова.

0 голосов
/ 23 марта 2020

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

...