Добрый вечер.
Интересует вопрос по boost::serial_port.
В порт передается объект io_service. Открываю порт, делаю чтение, потом закрываю порт. Если в io_service остаются handler'ы то повторно порт открыть нельзя. Сам же io_service удаляет handler's только при вызове деструктора. Те удается снова открыть порт когда сделан shut_down (те был вызван деструктор) для io_service, в противном случае выдает ошибку access denied.
Если делать так получается вообще что-то невразумительное:
class MySerialPort : public std::enable_shared_from_this<MySerialPort>
{
MySerialPort()
: Port(Service)
{
}
...
void Read()
{
auto self(shared_from_this());
boost::asio::async_read(Port, boost::asio::buffer(&Buffer, 1),
[this, self](const boost::system::error_code& error, std::size_t bytes_transferred)
{
...
...
}
}
boost::io_service Service;
boost::serial_port Port;
}
Если где-то есть
std::shared_ptr<MySerialPort> MyPort;
..
..
а потом где-то где-то
MyPort.reset();
то если в Service есть(например после вызовов Read) ссылки на объект MyPort, то по сути деструктор MyPort не будет вызван.
Service останется где-то висеть с ссылками на MyPort. Утечка памяти. Порт повторно открыть будет нельзя (выдает acces denied).
Правильно понимаю, что io_service всегда должен передаваться в MySerialPort только извне и уничтожать(вызов деструктора) всегда раньше чем сам MySerialPort?
При этом сам MySerialPort объект тоже должен уничтожаться ибо ссылается на io_service.?
а это что за чудо? =))
у тебя что, на каждый объект MySerialPort создается по io_service`у?
доку не пробовал читать? ну, или, экзамплы посмотреть
срань какая..
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, HolyNick, Вы писали:
HN>Можно можно сделать shutdown для сервиса, этот , вариант, вроде работает.
у io_service нет метода shutdown(), и у serial_port — тоже.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Вообще хочу использовать (и раньше использовал) один сервис. Но одним сервисом на несколько портов не получается разрулить ситуацию:
1. Закрываю порт
2. В сервисе в очереди остались какие-то задания для порта
3. Снова открываю тот же порт — в результате access denied.
Если был вызван деструктор (или shutdown) для сервиса, то порт снова нормально(пункт 3) открывается.
Может и не в деструкторе\shutdown дело, пока не понял.
HN>В порт передается объект io_service. Открываю порт, делаю чтение, потом закрываю порт. Если в io_service остаются handler'ы то повторно порт открыть нельзя.
А что означает, "остаются хендлеры"? " Это зарегестрированные на асинхронное исполнение по
поступлению события? Ну тогда сам порт ИМХО нужно уничтожать в одном из таких хендлеров
после того и в результате того, как они будут исполнены. В противном случае нужно юзать синхронные
обрабтчики. Никаких async*
Здравствуйте, HolyNick, Вы писали:
HN>Вообще хочу использовать (и раньше использовал) один сервис. Но одним сервисом на несколько портов не получается разрулить ситуацию: HN>1. Закрываю порт
о чем речь?
HN>2. В сервисе в очереди остались какие-то задания для порта
хз что за "порт" и как он закрывается, но с сокетами и файловыми дескрипторами — при закрытии — все хендлеры выполняются сразу же, с соответствующим error_code.
HN>3. Снова открываю тот же порт — в результате access denied.
хз что за "порт", и как он открывается...
HN>Если был вызван деструктор (или shutdown) для сервиса, то порт снова нормально(пункт 3) открывается. HN>Может и не в деструкторе\shutdown дело, пока не понял.
хз что за shutdown, такое я видел только у сокета...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
S>А что означает, "остаются хендлеры"? " Это зарегестрированные на асинхронное исполнение по S>поступлению события?
Да.
S>Ну тогда сам порт ИМХО нужно уничтожать в одном из таких хендлеров S>после того и в результате того, как они будут исполнены. В противном случае нужно юзать синхронные S>обрабтчики. Никаких async*
А как порт уничтожить, если хендлер висит в очереди в сервисе и он не вызывается на обработку.
(Те может че-то такое и можно провернуть — изучать надо.)
Да и постоянно порт создавать\удалять можно конечно, но хотелось бы обойтись.
Хочу асинхронные
Те такая (примерно пишу) штука вот уже не будет работать:
boost::asio::io_service service;
boost::asio::serial_port port(service);
port.open(portAddress.toStdString());
if (port.is_open())
{
std::uint8_t Buffer;
boost::asio::async_read(port, boost::asio::buffer(&Buffer, 1),
[this](const boost::system::error_code& error, std::size_t bytes_transferred)
{
//допустим ничего считать нельзя и просто будет поставлено задание в очередь
});
port.close();
port.open(portAddress.toStdString()); //access denied
}
Здравствуйте, HolyNick, Вы писали:
HN>А как порт уничтожить, если хендлер висит в очереди в сервисе и он не вызывается на обработку.
Обработку в виде вызова асинхронного хендлера может вызвать внешнее событие,
например, появление данных на дескрипторе, доступных на чтение, или появление
возможности записи. Если таковых событий не произошло, то зачем уничтожать порт?
Если они произошли, то будет вызван хендлер, в котором проведём все работы
по вводу/выводу, после чего или повесим новый хендлер, для ожидания новых событий,
или грохнем сокет/порт. Тогда в внутренних очередях io_service не будут оставаться,
осиротевшие хендлеры.
Здравствуйте, HolyNick, Вы писали:
HN>Те такая (примерно пишу) штука вот уже не будет работать: HN>
HN> port.close();
HN>
.close() по идее должен завершать все хэндлеры с boost::asio::error::operation_aborted.
Этот код точно не работает? А если создать полностью новый serial_port, после деструкции старого? (можно использовать optional<serial_port>)
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>.close() по идее должен завершать все хэндлеры с boost::asio::error::operation_aborted.
нет. при close(), хендлеры вызовутся с end_of_file, а при cancel() — operation_aborted
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
вообще, такое ощущение, что ТС не понимает что делает/хочет_сделать, и не понимает что говорит. его ответы/вопросы и ответы на вопросы — какие-то непоследовательные, оторванные...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
EP>Этот код точно не работает? А если создать полностью новый serial_port, после деструкции старого? (можно использовать optional<serial_port>)
У меня получилось повторно открыть порт, только с новым объектом порта и (одновременно) новым объектом io_service для него.
При этом предыдущий объект порта И его объект io_service должны быть уничтожены(вызван деструктор для них).
Здравствуйте, niXman, Вы писали:
EP>>.close() по идее должен завершать все хэндлеры с boost::asio::error::operation_aborted. X>нет. при close(), хендлеры вызовутся с end_of_file, а при cancel() — operation_aborted
Я же ссылку привёл, а по ней:
This function is used to close the serial port. Any asynchronous read or write operations will be cancelled immediately, and will complete with the boost::asio::error::operation_aborted error.
cancel() тоже не помогает.
Насколько я видел код close() просто закрывает хендл порта. Но, опять же насколько я представляю, а представляю я пока слабо, внутри (всей кухни управления COM портом) используется механизм
портов завершения вводы\вывода и если какая-то из функций этого механизма "держит" хендл, то фактически закрытия не происходит при вызове close().
Те перед close() надо сделать еще какие-то правильные действия в правильной последовательности.
Точно не могу сказать, вроде, нет.
Ты можешь вызвать port.close(), а потом у сервиса service.poll() или service.run() и тогда он вызовет хендлер с какой-то ошибкой(типа порт закрыт) соответственно.
Но это не значит, что Windows HANDLE порта правильно закрылся после этого...хотя — ...надо разбираться)))
Здравствуйте, HolyNick, Вы писали:
HN>Точно не могу сказать, вроде, нет. HN>Ты можешь вызвать port.close(), а потом у сервиса service.poll() или service.run() и тогда он вызовет хендлер с какой-то ошибкой(типа порт закрыт) соответственно.
Если .close() не вызывает, хотя документация говорит что должен — то по всей видимости там баг, и нужно открывать ticket.
Какая версия boost? И можешь привести минимальный пример однозначно воспроизводящий проблему (можно добавить вывод в cout внутри хэндлера, до и после вызова close/cancel).
Бага там нет, если ты запустил где-то service.run(), а потом вызвал port.close(), то он все обработчики вызовет.
Я-то service.run() вообще никогда не вызываю(не использую), только service.poll(), поэтому и после закрытия(port.close()) порта мне нужно вызвать service.poll(), как я указал в предыдущем примере.
PM>Телепатически предполагаю что все дело в выделенном — для нормальной работы асинхронного I/O у io_service нужно вызывать run(), run_once() или poll().
Да. И еще похоже, что нужно делать вызов reset(), о чем в общем-то написано в исходниках :
boost::asio::io_service service;
std::shared_ptr<boost::asio::serial_port> port(new boost::asio::serial_port(service));
port->open("COM3"); //OK
char buffer;
boost::asio::async_read(*port, boost::asio::buffer(&buffer, 1),
[port](boost::system::error_code error, std::size_t bytes_transferred)
{
int i = 0;
i++;
});
port->close();
service.poll();Вызовется обработчик из предыдущего async_read
service.reset();если не вызвать, то следующая команда poll не вызовет обработчик
port->open("COM3");//OK
char buffer2;
boost::asio::async_read(*port, boost::asio::buffer(&buffer2, 1),
[port](boost::system::error_code error, std::size_t bytes_transferred)
{
int i = 0;
i++;
});
port->close();
service.poll();Вызывает обработчик, только если был вызов reset()
port->open("COM3");//OK, только если был вызов reset(), в противно случае ACCESS DENIED и исключение
Если я использую в программе два COM(boost::asio::serial_port) порта каждый из которых использует свой отдельный объект io_service, могу ли я работать(делать вызовы poll()) с портами(и соответстсвенно сервисами) в разных потоках? Какие там подводные камни? Или надо для каждого порта запускать свой поток и опрашивать порт только в нем?
Спасибо.
X>а зачем тебе два io_service`а? или ты все еще продолжаешь писать "лишь бы работало"?
Пока разбираюсь. Но вопрос актуален даже если один и тот же сервис на оба порта.
X>а зачем тебе дополнительные потоки(threads)? чем асинхронный IO не угодил?
Основной поток реагирует на нажатия кнопочек окошка, второй пишет\читает(выполняет задачу) из порта.
Здравствуйте, HolyNick, Вы писали:
HN>Основной поток реагирует на нажатия кнопочек окошка, второй пишет\читает(выполняет задачу) из порта.
так интегрируй io_service::poll_one() в event loop твоей апликухи. и не нужно никаких дополнительных потоков.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, niXman, Вы писали:
X>Здравствуйте, HolyNick, Вы писали:
HN>>Основной поток реагирует на нажатия кнопочек окошка, второй пишет\читает(выполняет задачу) из порта. X>так интегрируй io_service::poll_one() в event loop твоей апликухи. и не нужно никаких дополнительных потоков.
Да, согласен. (спасибо за подсказку)
ps: просто с парой потоков, при некотором условии, переставали вызываться обработчики(handler'ы) порта — хотелось понять почему (на будущее)
Здравствуйте, HolyNick, Вы писали:
HN>Да, согласен. (спасибо за подсказку)
был случай в практике.
в некоторой конторе написали(до моего там появления) ГУЙ к некоторой проге. эта прога, в законченном виде, должна была общаться с некоторым удаленным процессом, посредством сокета.
так вот, тот ГУЙ, был закожен на основе фреймворка той конторы(поверх API VxWorks), которая специализировалась на RTOS. ну и разработчики фреймворка не предусмотрели возможность использовать event loop их фреймворка. а я любитель минимализма, и, прежде чем заюзать дополнительный поток, я трижды подумаю, особенно с учетом того, что тот фреймворк писал не я, и я зх, когда и где "выстрелит" баг из-за дополнительного потока(синхронизация, и все такое)...
в итоге, я в апликуху добавил объект фреймворкого таймера, который каждые 3 мс. звал io_service::poll_one() =)
работает отлично, до сих пор. в простое, когда на сокете нет операций, нагрузка на проц составляет ~2-7 процентов.
но решение, считаю, дико костыльным...
HN>ps: просто с парой потоков, при некотором условии, переставали вызываться обработчики(handler'ы) порта — хотелось понять почему (на будущее)
во-первых — я не понимаю твою задачу.
во-вторых — ты ужасный объясняльщик.
в-третьих — ты не отвечаешь на вопросы.
хз, чем я тут могу помочь...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)