asio posix stream_descriptor async_read не завершается на MAC - PullRequest
1 голос
/ 28 февраля 2020

У меня другое поведение на MA C против Linux (ubuntu), когда дело доходит до async_read / async_write на asio::posix::stream_descriptor. На моей ма c итерация выполняется один раз (вывод iter 13), а затем зависает на второй итерации в std::future<...>::get() из-за того, что дескрипторы завершения async_read(...) и async_write(...) никогда не вызываются. На моей машине Linux вывод соответствует ожидаемому, то есть

iter 13
iter 14

Интересно, что если я переключу порядок чтения / записи, то он будет работать правильно на ma c. Кроме того, если я всегда читаю / записываю данные размером не более 8192=(1<<13) байт, то будут вызываться дескрипторы завершения чтения / записи.

Файл, которому назначен stream_descriptor, является именованным каналом, созданным mkfifo(...). Ниже приведен минимальный пример, который я смог сделать.

Кто-нибудь знает, почему это висит на ма c и есть ли исправление?

#include "boost/asio.hpp"
#include <future>
#include <iostream>
#include <cstdio>


int main()
{
    using stream_descriptor = boost::asio::posix::stream_descriptor;

    // setup the background thread.
    boost::asio::io_context ioc;
    auto worker = std::make_unique<boost::asio::io_context::work>(ioc);
    std::thread thrd([&] {ioc.run(); });

    // remove and make the named pipe.
    std::string name = "/home/peter/myFifo";
    std::remove(name.c_str());
    if (mkfifo(name.c_str(), 0666))
        throw std::runtime_error("error opening fifo");

    // open the two ends of the named pipe. The 
    // std::async is there since the first will block
    // until the second is opened.
    int ifd, ofd;
    auto f = std::async([&]() {
        ifd = open(name.c_str(), O_RDONLY);
    });
    ofd = open(name.c_str(), O_WRONLY);
    f.get();

    // create the asio adapter
    stream_descriptor in(ioc), out(ioc);
    in.assign(ifd);
    out.assign(ofd);

    // these lines seems to make no difference.
    //in.non_blocking(true);
    //out.non_blocking(true);

    // iterate the the messages sizes that are causing issues.
    for (int i = 13; i < 15; ++i)
    {
        int size = (1 << i);
        std::vector<char> buff(size);
        boost::asio::mutable_buffer mb(buff.data(), buff.size());
        std::promise<boost::system::error_code> p0, p1;

        boost::asio::async_read(in, mb,
            [&](const boost::system::error_code& ec, size_t bt) {
                p1.set_value(ec);
            });
        boost::asio::async_write(out, mb,
            [&](const boost::system::error_code& ec, size_t bt) {
                p0.set_value(ec);
            });

        p0.get_future().get();
        p1.get_future().get();

        std::cout << "iter " << i << std::endl;
    }

    // cleanup
    worker.reset();
    thrd.join();
    return 0;
}
...