1 | ||||||
Подвисает при чтении COM порта22.11.2013, 03:00. Показов 11198. Ответов 23
Метки нет Все метки)
(
Доброго времени суток, сделал программу, которая читает данные из COM порта, строка кода которая считывает данные стоит в компоненте timer с периодичностью n, поставил т.к. threading вызывает зависание программы, это неприемлемо. Но в таймере почему-то эта строка тоже зависает, данные то отображаются с COM порта на форме и обновляются но работать с формой невозможно. Что можно придумать? Возможно проверка
if (данные на ком порте не пустые) погнали...
0
|
|
22.11.2013, 03:00 | |
Ответы с готовыми решениями:
23
Зависает форма при чтении из порта Чтение из COM порта, При чтении из порта зависает read() «Зависает» при чтении com порта Зависает при чтении com порта |
26 / 26 / 1
Регистрация: 19.09.2012
Сообщений: 123
|
|
22.11.2013, 03:15 | 2 |
Просто читать из порта надо в отдельном рабочем потоке, посмотрите в сторону async/await. Инициировать чтение можете продолжать по таймеру, но само чтение лучше реализовать в отдельной async-функции, после await'а которой записывать результат в label'ы. К сожалению, не могу сейчас написать код, но наверное разберётесь...
1
|
23.11.2013, 16:50 [ТС] | 4 | ||||||||||
Все разобрался!
Вот код программы:
0
|
48 / 48 / 22
Регистрация: 18.11.2013
Сообщений: 92
|
||||||
23.11.2013, 22:18 | 5 | |||||
кхм, а то что в обработчик дуворк зациклен это так задумано?)
и зачем вы передаете 100 в RunWorkerAsync? вы же их нигде не используете а вообще тут нужно знать как и что приходит в последовательный порт (что на том конце провода) если подключенный девайс шлет одну за другой строчки с интервалом в 15 секунд как я понял...я бы сделал как то так
1
|
23.11.2013, 22:34 [ТС] | 6 | |||||
На другой стороне arduino mega, шлет значения пока с датчика расстояния или просто текст, но планирую с датчиков температуры и влажности. Вот код на arduino:
Что означает 1000 в worker.RunWorkerAsync(1000); В в этом градуснике, я собираюсь посылать значения с большим (1000++) интервалом, а что если arduino высылает их каждые 50мс, 25мс, как их лучше принимать в C#? Спасибо!
0
|
48 / 48 / 22
Регистрация: 18.11.2013
Сообщений: 92
|
|
23.11.2013, 23:05 | 7 |
1000 это просто передаваемый параметр обработчику DoWork
его можно вытащить из аргумента передаваемого в событие DoWork - DoWorkEventArgs e что собственно и сделано в коде, далее это значение используется чтобы усыпить поток для гарантированного получения 2х строк, но как оказалось они шлются с интервалом в ~1100мс, поэтому можете изменить его на 300-500 если это градусник, вам не нужны такие интервалы, температура вещь инертная, но если все же если понадобится, то конечно же лучше принимать в событии DataReceived ком порта, кидать полученные данные в какой то промежуточный буфер, при этом сделать какой нибудь элементарный протокол (чтобы отличать эти 2 сообщения друг от друга) и парсить (анализировать) принятые данные (это будет в DoWork скорее всего) а потом уже что то делать с данными(это в RunWorkerCompleted) Добавлено через 13 минут а стоп, а на кой черт посылать значения температуры в цельсиях и фаренгейтах? посылайте только одно и конвертируйте на приемной стороне, только сейчас понял, что там у вас было ![]()
1
|
26 / 26 / 1
Регистрация: 19.09.2012
Сообщений: 123
|
||||||
23.11.2013, 23:21 | 8 | |||||
Вот так это будет выглядеть с async/await, и по сути ничего не надо больше:
1
|
48 / 48 / 22
Регистрация: 18.11.2013
Сообщений: 92
|
|
23.11.2013, 23:36 | 9 |
Ithilgwau, у вас "небезопасный" прием, мы просто считываем 2 строчки как и в первоначальном варианте
конечно если цель оправдывает средства...но я бы так не сделал у ТСа вообще девайс шлет эти 2 строчки с ~1100мс интервалом, а таймер взведен на 15 секунд, считываются не все данные...буфер ком порта по дефолту имеет вместимость в 4096 (вроде) байта, при таком подходе он просто переполнится и начнет перезаписываться (или вбросит исключение, не знаю точно), что приведет к потере данных
1
|
26 / 26 / 1
Регистрация: 19.09.2012
Сообщений: 123
|
|
24.11.2013, 02:15 | 10 |
Вопрос был о том, как сделать, чтобы UI не зависал. Я на это и ответил. А насчёт буфера ком-порта и т.д. - это уже другой вопрос
![]()
1
|
26 / 26 / 1
Регистрация: 19.09.2012
Сообщений: 123
|
||||||
24.11.2013, 10:38 | 12 | |||||
Так-то потоки это не очень просто конечно, особенно если только начинаешь в них разбираться... Но создатели C# - молодцы. Придумав async/await, они очень упростили реализацию разработчиками значительной части задач...
Но вот если делать так, чтобы поток читал COM-порт беспрерывно, то async/await тут уже не обойтись... Тут придётся создавать поток (Thread.Start) при запуске формы, в этом потоке в бесконечном цикле читать порт и через диспетчер устанавливать label'ы на форме (через диспетчер - потому что напрямую это делать не из главного потока нельзя, у нас это разруливал await, а сейчас некому). Последнее делается как-то так:
Добавлено через 11 минут Ой, у тебя же Forms, а не WPF... Вот тут хорошо про диспетчер объясняется (и для Forms, и для WPF) ![]()
0
|
48 / 48 / 22
Регистрация: 18.11.2013
Сообщений: 92
|
|
24.11.2013, 23:53 | 13 |
ради интереса расчехлил эклипс и какую то AVRку и проверил с железом
вариант с воркером и DataReceived "небезобасный" с точки зрения многопоточности, событие DataReceived происходит не в основном потоке, и походу если воркер запущен в этом потоке событие RunWorkerCompleted происходит так же в нем, в студии при отладке вбрасывается InvalidOperationException, посему возможно Invoke остается единственным "правильным" решением
0
|
26 / 26 / 1
Регистрация: 19.09.2012
Сообщений: 123
|
|
25.11.2013, 00:09 | 14 |
Я уже достаточно работал с потоками с C#, но про этот worker слышу впервые
![]()
0
|
48 / 48 / 22
Регистрация: 18.11.2013
Сообщений: 92
|
||||||
25.11.2013, 02:09 | 15 | |||||
в общем виде как то так
0
|
26 / 26 / 1
Регистрация: 19.09.2012
Сообщений: 123
|
|
25.11.2013, 02:42 | 16 |
Что-то Вы, сударь, нагородили... Код, в котором есть Sleep - это всегда ненормальный код, это всегда хак. Просто никогда и нигде не используйте Sleep, только в целях отладки (чтобы, например, сэмулировать какую-то продолжительную операцию). Здесь нужно использовать или ReadLine или Read. И не понадобится никаких port_DataReceived. Всё это делается проще и понятнее, как я писал выше:
Ииииии всё ![]()
0
|
48 / 48 / 22
Регистрация: 18.11.2013
Сообщений: 92
|
|
25.11.2013, 14:35 | 17 |
но
это тоже хак) вы знаете что происходит при попытке прочитать несуществующий порт? (девайс отвалился) приложение намертво зависает ![]() а вы знаете что может быть в первоначально рассматриваемом случае ТСа? девайс и приложение работают асинхронно относительно друг от друга, нет никакой гарантии что чтение не начнется в момент прихода нового сообщения (скорость обмена значительно ниже скорости считывания) по хорошему тут приемлем только событийный режим, да, мой вариант "урощен", да, там есть слип в асинхронном потоке (никому не мешающий), да, по хорошему там должен быть какой нибудь FIFO буфер и использование BytesToRead и прочего, а обмен данным должен быть осуществлен по какому нибудь протоколу (хотя бы самопальному)...но это уже другая история ![]()
0
|
26 / 26 / 1
Регистрация: 19.09.2012
Сообщений: 123
|
|
25.11.2013, 14:54 | 18 |
Нет, это не хак, это обычная нормальная практика. И, кстати, я уточнил, что цикл не должен быть бесконечным по-хорошему, а надо проверять на булевскую переменную, чтобы корректно выйти из него.
Да и Бог с ним, пусть начнётся. У нас отдельный поток, и пусть читает как ему угодно.
В любом потоке Sleep - зло. Я просто не понимаю, почему нельзя сделать просто Read или ReadLine, которые блокируют поток до завершения чтения?
0
|
48 / 48 / 22
Регистрация: 18.11.2013
Сообщений: 92
|
|
25.11.2013, 15:31 | 19 |
Ithilgwau, не, Вы не поняли
во-первых я сделал акцент на событийном режиме, я не оправдываю слип, во-вторых зачем городить еще один поток если мы имеет DataReceived? я же говорю, если девайс отвалится, порт будет "типа открытый" (IsOpen == true) но поток выполняющий ReadLine застопоривается (я там выше описался, написал "приложение" вместо "поток"), а в случае DataReceived просто не будет вызываться... Не по теме: широко известный Modbus работающий по таймаутам вы тоже предложите в бесконечном цикле опрашивать ReadLine'ом ? ;)
0
|
26 / 26 / 1
Регистрация: 19.09.2012
Сообщений: 123
|
|
25.11.2013, 15:45 | 20 |
Так дело в том, что DataReceived просто не нужен. Он только усложняет всё. Пусть среда сама разруливает, как и что она читает, и возвращает нам управление, когда уже всё прочитано, тогда ни о каких задержках и кол-ве данных в буфере беспокоиться уже не нужно
Он не застопориться, если поставить timeout чтения (который и так наверное по умолчанию задан). И пусть порт будет открыт на здоровье, как только по нему придут данные, Read их вернёт.
0
|
25.11.2013, 15:45 | |
Помогаю со студенческими работами здесь
20
При чтении com порта зависает приложение
Откуда при чтении из COM-порта берутся 99 байт? Работа функции FlushFileBuffers при синхронном чтении из Com-порта Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |