| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Общие вопросы по .NET и C# > Потоки, взаимодействие и работа |
| Автор: WantToProg 15.2.2010, 10:38 | ||
| Доброе время суток. Извиняюсь что так написал название темы, но суть оно отражает. А проблема в следующем: Я пишу код, который в одном потоке считывает данные из файла и передает их в последовательный порт компьютера. Второй поток возникает по событию DataReceived. Так вот проблема возникла в связи с тем, что мне необходимо закрывать порт по окончании приема данных, и открывать его снова, при отправке. Но вероятно по причине параллельности выполнения потоков, порт не успевает закрываться. Но если проверяю проверяю с точками останова, ошибки не возникает. Подскажите пожалуйста каким образом можно избежать данной ошибки. Насколько я понимаю, необходимо сделать так, что бы первый поток не выполнялся пока не завершится поток по событию DataReceived, но как это сделать, я не знаю. Проблемный код предоставляю ниже:
PS: Причина, по которой порт необходимо закрывать по окончании приема данных, заключается в том, что в файле, который я читаю в начале порты могут быть разные (образец строки из файла 1!2380!23d8!COM3!1!0003!), а считывать и получать данные от устройств мне необходимо последовательно. PPS: Я не программист, так что сильно не ругайте за код, просто приходится параллельно выполнять еще и такие задачи. Прислушаюсь к хорошим советам по улучшению кода. |
| Автор: Экскалупатор 15.2.2010, 13:22 | ||||||
во-первых, надо закрывать порт не в if, а просто в конце кода. т.е. закрывать в любом случае.
во-вторых, попробуй использовать блок
оберни в него блок кода который работает с портом. должно получиться как то так:
в таком случае все манипуляции с закрытием и ожиданием должны отпасть. по поводу организации кода говорить надо много и долго. по сути тут надо переделывать все. возьми книжку: Стив Макконел "Совершенный код". Мартин Фаулер "Рефакторинг". |
| Автор: Экскалупатор 15.2.2010, 14:53 | ||
значит в таком случае у тебя ошибка в организации всего процесса. как то странно все работает. такое ощущение что сначала слушается порт, а потом открывается новый и при следующем цикле используется старый открытый порт. |
| Автор: WantToProg 15.2.2010, 15:12 | ||
тут наверно я что то не понимаю. Весь код предоставлен выше, ничего другого нет. Если я выполняю дебагинг то получаю следующее: 1. Запускается цикл, в котором получаем необходимые значения для отправки в порт 2. Создается экземпляр порта с необходимыми параметрами 3. Порт открывается 4. Выполняется функция отправки данных 5. Возвращается на место вызова функции 6. Порт закрывается //Вы советовали 7. Параллельно запускается прием данных с порта по событию 8. Данные не могут быть получены и мы получаем Exception IsClosed Прошу, объясните поподробнее, что должно было произойти по вашему мнению. Возможно я что то не так сделал. |
| Автор: Экскалупатор 15.2.2010, 15:43 | ||
я не учитывал что нужно получать данные. в таком случае нужно ждать пока закончиться прием данных, а потом все закрывать и начинать сначала. |
| Автор: uranpro 15.2.2010, 16:20 | ||
из справки =) |
| Автор: WantToProg 15.2.2010, 16:31 | ||
Не помогает, т.к. процедура чтения данных по событию, выполняется параллельно потоку Do(). И открытие порта инициируется в этом потоке до того, как порт будет закрыт и данные будут прочитаны Чувтсвую в коде есть ошибка, но найти не знаю как. Мне все таки кажется есть возможность не выполнять цикл процедуры Do(), до тех пор, пока не будут получены данные. А вот как это сделать, очень прошу у вас совета |
| Автор: Экскалупатор 15.2.2010, 16:46 | ||
uranpro, да. согласен, но тут вроде немного не так все. тут смысл в том что в одном потоке открывается порт, а второй поток этот открытый порт использует(ну на сколько я понял из объяснений). получается что второй поток зависит от первого но он об этом не знает. отсюда и лезет ошибка.
но ведь это не правильно? на сколько я понимаю сначала идет отправка чего то в порт, а потом читается ответ. ну так надо так и сделать этот процесс: открыть порт отправить прочитать ответ закрыть порт или ставить событие которое будет ждать команды окончания чтения из порта, и будет закрывать порт и только потом начинать новую итерацию цикла. |
| Автор: WantToProg 15.2.2010, 18:50 | ||
Вот, вы меня отлично поняли. Открыть порт, отправить - первый поток из процедуры Do() Прочитать ответ по событию newPort.DataReceived += new SerialDataReceivedEventHandler(newPort_DataReceived); Вот тут описание работы события http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx Как мне сделать, чтоб не возникло проблемы параллельного выполнения потока. Может быть вообще поток лишнее? Но тогда в какую сторону копать? |
| Автор: Экскалупатор 15.2.2010, 20:01 |
| WantToProg, я, конечно, не возьмусь утверждать, но мне кажется что поскольку ответ всегда читается после отправки, то нет никакого смысла делить этот процесс на два параллельных потока. все должно быть по порядку: открыть, отправить, прочитать, закрыть, следующая итерация. я это и пытался сказать, что деление на потоки в данном случае мне кажется бессмысленным, поскольку эти операции идут одна за другой. единственное нужно будет учесть превышение времени ожидания ответа. |
| Автор: WantToProg 16.2.2010, 08:02 | ||
| Экскалупатор, В том то и проблема, я не знаю как сделать все это в одном потоке :( Обработку события newPort.DataReceived, я взял с msdn. А другого варианта я даже не вижу. Если бы это был сетевой поток (NetworkStream), то я обошелся бы событием DataAvailable, но как проверить наличие данных в последовательном порту, я не знаю. И еще, дело в том, что есть другой вариант считывания данных: SerialPort.ReadExisting() Который возвращает System.String, но мне надо получить поток байтов. Для этого есть заметка в этой http://msdn.microsoft.com/ru-ru/library/system.io.ports.serialport.readexisting.aspx
Не понимаю как это сделать. |
| Автор: Экскалупатор 16.2.2010, 12:16 | ||||
WantToProg, можно попробовать "усыпить" поток на время выполнения получения данных. ты видно пытался это сделать:
но так усыпляется тот поток в котором ты вызываешь этот метод. но при этом поток в котором открывается порт продолжает работать и закрывает порт. из MSDN
может это можно как то использовать? получается запрашиваешь число байтов, потом их считываешь, а потом продолжаешь выполнять метод. |
| Автор: uranpro 16.2.2010, 12:38 |
| а если сделать метод не Do, а DoNext(...) и вызывать в конце DataReceived? |
| Автор: WantToProg 16.2.2010, 12:49 | ||
Во, я так и сделал. В принципе работает, хотя помоему это неправильно. Думаю правильнее было бы блокировать первый поток пока не закончится второй. А проще было бы читать сразу по типу SerialPort.ReadExisting(). Только вот последовательность байтов не преобразовывая в строку. Если бы вы еще и это подсказали, был бы просто счастлив |
| Автор: Экскалупатор 16.2.2010, 13:00 | ||
ну я и имел ввиду, что тут не правильно блокируется. потому что блокируется поток в котором принимаются значения. а надо блокировать тот в котором открывается порт. кстати, может попробовать просто открыть порт, выполнить ВСЕ записи и чтения, а потом закрыть его? хотя держать постоянно открытым соединение тоже не выход... по поводу чтения байтов: http://msdn.microsoft.com/ru-ru/library/system.io.ports.serialport.readbyte.aspx. правда оно читает 1 байт. так что можно в цикле запускать побайтовое чтение до тех пор пока не будет прочитан конец потока, или запрашивать количество доступных байтов. Добавлено через 48 секунд ну или можно строку конвертировать в массив байтов. |
| Автор: WantToProg 16.2.2010, 14:07 | ||
В том то и дело, я не знаю, чем и когда закончится пакет получаемых данных. Если в tcp сокете есть DataAvailable, то тут этого нет. А только буффер DataRecieved И int byteRecieved = port.BytesToRead; Эх, как бы это все заставить работать нормально. Просто усыплять цикл искуственно, кажется не правильным подходом, происходит искусственная задержка, что само собой не хорошо. А здесь самая большая загвоздка. Я пробовал конвертировать в массив байтов. Получается совсем не то, что приходит в байтах (проверял и снифером и по DataRecieved) |
| Автор: WantToProg 16.2.2010, 14:37 |
| doublepost |
| Автор: Экскалупатор 16.2.2010, 14:52 | ||
из MSDN ReadByte возвращает Байт, приведенный к типу Int32, или -1, если считан конец потока. |
| Автор: WantToProg 16.2.2010, 15:33 | ||||
На этом спасибо, но я вроде решил проблему
Все оказалось проще чем я думал |