Nano Hash - криптовалюты, майнинг, программирование

Boost asio путается со стандартным вводом?

Эта программа читает из стандартного ввода (через iostream) и записывает в стандартный вывод (через boost/asio):

#include <boost/asio.hpp>
#include <cassert>
#include <iostream>
#include <string>

boost::asio::io_service io_service;
boost::asio::posix::stream_descriptor out(io_service, ::dup(STDOUT_FILENO));
std::string line = "";

static void handler(
    boost::system::error_code const &,
    std::size_t
) {
    assert(std::getline(std::cin, line));
    line += "\n";
    async_write(out, boost::asio::buffer(line), handler);
}

int main()
{
    async_write(out, boost::asio::buffer(line), handler);
    io_service.run();
}

сборка: g++ -std=gnu++1y -O0 -g3 -o out in.cxx -lboost_system -lboost_thread

запустить: cat | ./out

вывод:

foo [TERMINAL INPUT]
foo
bar [TERMINAL INPUT]
cat: -: Resource temporarily unavailable
bar
out: in.cxx:14: void handler(const boost::system::error_code&, std::size_t): Assertion `std::getline(std::cin, line)' failed.
Aborted (core dumped)

cat получает EAGAIN из write() на свой стандартный вывод, обрабатывает его как ошибку и закрывает канал. В свою очередь getline() терпит неудачу, и программа прерывается.

Похоже, что asio устанавливает стандартный ввод программы (который является стандартным выводом cat, см. Странный бросок исключения - присвоить: Операция не разрешена) на неблокирующую. У него нет очевидной причины делать это, потому что он работает только со стандартным выводом.

Если я правильно понял, это ошибка asio? Есть ли обходной путь?

libboost1.58-dev/xenial-updates,now 1.58.0+dfsg-5ubuntu3.1 amd64 [installed]
g++/xenial,now 4:5.3.1-1ubuntu1 amd64 [installed]
28.02.2017

  • Я не знаю, как вы делаете вывод, что asio настраивает стандартный ввод программы на неблокирующий. Я не вижу такой логики. И да, если вы перенаправите вывод своей программы в файл, вы ПОЛУЧИТЕ assign: operation not permitted, потому что асинхронный ввод-вывод не поддерживается для файлов в Linux. 28.02.2017
  • @sehe: cat говорит -: Resource temporarily unavailable - значит, кто-то должен установить неблокирующий дескриптор файла. Если это была не cat или оболочка, то должна быть программа, т.е. asio. 01.03.2017
  • @sehe: я не вижу здесь ошибки assign: operation not permitted. Я ссылаюсь только на то, где я узнал, что оба конца канала оболочки имеют один и тот же файловый дескриптор. 01.03.2017
  • Ой. Ты должен был сказать это. Кроме того, я нигде не вижу, где это утверждение сделано (оба конца канала оболочки имеют один и тот же файловый дескриптор). Что еще более важно, я думаю, что это ложно и не имеет значения. (fds в любом случае являются локальными для процесса, нет полезное сравнение между fd из разных процессов) 02.03.2017
  • @sehe: Ну, это не один и тот же файловый дескриптор, но их файловые дескрипторы относятся к одному и тому же открытому файлу. Таким образом, флаги, которые устанавливает один (например, O_NONBLOCK), будут видны другому. См. мой пример на ideone.com/r4TVZd. 02.03.2017

Ответы:


1

Вы вызываете неопределенное поведение здесь:

async_write(out, boost::asio::buffer(string + "\n"), handler);

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

EDIT На самом деле, даже если переменная не была локальной, + "\n" делает ее временной!

Вот предлагаемое исправление для этой простой программы:

Жить на Coliru

#include <boost/asio.hpp>
#include <cassert>
#include <iostream>
#include <string>

boost::asio::io_service io_service;
boost::asio::posix::stream_descriptor out(io_service, ::dup(STDOUT_FILENO));
std::string input_buffer;

static void handler(boost::system::error_code /*error*/, std::size_t /*bytes_transferred*/) {
    if (std::getline(std::cin, input_buffer)) {
        input_buffer += "\n";
        async_write(out, boost::asio::buffer(input_buffer), handler);
    }
}

int main() {
    async_write(out, boost::asio::buffer(""), handler);
    io_service.run();
}

Я не уверен, что это решит все ваши проблемы, но, по крайней мере, вам нужно это исправить, чтобы иметь возможность рассуждать о своей программе вообще

28.02.2017
  • Ты прав. Но на самом деле это не решает проблему, см. мою правку. 01.03.2017
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..