Форум программистов, компьютерный форум, киберфорум
Visual Basic .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.90/21: Рейтинг темы: голосов - 21, средняя оценка - 4.90
7 / 5 / 0
Регистрация: 15.05.2015
Сообщений: 350
1

Как вынести работу с SerialPort в отдельный поток?

03.04.2017, 17:27. Показов 4060. Ответов 12
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Подскажите как правильно работать с потоками?

Работаю с Serial Com Port, снимаю с него текстовые данные, как цикл выкинуть в отдельный поток? Как сделать чтобы другие кнопки формы не повисали? Форма не висла?

VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    Private Sub cb_start_Click(sender As Object, e As EventArgs) Handles cb_start.Click
        If SerialPort1.IsOpen Then
            SerialPort1.RtsEnable = False
            SerialPort1.DtrEnable = False
            SerialPort1.Close()
            Application.DoEvents()
        End If
 
        With SerialPort1
            .PortName = "COM5"
            .BaudRate = 9600
            .DataBits = 8
            .Parity = 0
            .StopBits = IO.Ports.StopBits.One
            .WriteTimeout = 2000
        End With
 
        Try
            SerialPort1.Open()
        Catch ex As Exception
            TextBox1.Text = ex.Message
        End Try
 
        While SerialPort1.IsOpen
            SerialPort1.RtsEnable = True
            Dim data_received As String = SerialPort1.ReadLine
            If TextBox1.Text.Length > 1 Then
                TextBox1.Text = TextBox1.Text & vbCrLf & data_received 'give an alert when data received
            Else
                TextBox1.Text = data_received 'give an alert when data received
            End If
            Application.DoEvents()
        End While
 
    End Sub
Добавлено через 9 минут
Выкинул вот так, нет данных в Textbox1 или не работает!

VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        If SerialPort1.IsOpen Then Dim gData As New Thread(AddressOf GetData)
 
    End Sub
 
    Private Function GetData()
        SerialPort1.RtsEnable = True
        While SerialPort1.IsOpen
            Dim data_received As String = SerialPort1.ReadLine
            If TextBox1.Text.Length > 1 Then
                TextBox1.Text = TextBox1.Text & vbCrLf & data_received 'give an alert when data received
            Else
                TextBox1.Text = data_received 'give an alert when data received
            End If
            Application.DoEvents()
        End While
        GetData = Nothing
    End Function
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.04.2017, 17:27
Ответы с готовыми решениями:

Как вынести обработчик глобального хука в отдельный поток?
Доброе время суток, уважаемые форумчане! Я делаю глобальный хук, с помощью класса, и хочу вынести...

Вынести работу с интернетом в отдельный поток
Хотел перенести работу с интернетом в программе в отдельный поток, но что то не могу сообразить. ...

Как вынести подключение к БД в отдельный поток?
Как вынести подключение бд в отдельный поток???Вот код программы: import android.os.Bundle;...

Как вынести код в отдельный поток?
Как вынести код в отдельный поток?

12
Модератор
Эксперт .NET
4314 / 3388 / 507
Регистрация: 27.01.2014
Сообщений: 6,186
03.04.2017, 17:28 2
у SerialPort есть событие DataArrived вроде. Обрабатывайте в нем полученные данные, ничего виснуть не будет и ненужно доп. потоки городить...
0
7 / 5 / 0
Регистрация: 15.05.2015
Сообщений: 350
03.04.2017, 17:33  [ТС] 3
Yury Komar, спасибо, проверю...

Ну а вообще как с потоками быть, не только здесь это мне понадобилось...

В моем примере как реализовать через Thread..., чтобы я знал на будущее?!
0
Эксперт .NET
11094 / 7013 / 1574
Регистрация: 25.05.2015
Сообщений: 21,176
Записей в блоге: 14
03.04.2017, 18:46 4
Цитата Сообщение от Yury Komar Посмотреть сообщение
DataArrived вроде
DataReceived. Неудобное событие. Возникает не когда все данные приняты, а где попало.
Цитата Сообщение от mostApi Посмотреть сообщение
В моем примере
ReadLine ждёт определённого символа. Надо чтобы в протоколе обмена он был завершающим.
Из потока нельзя обращаться к GUI.
DoEvents - костыль, выкручивайтесь без него. Тем более он тут не нужен.
Цитата Сообщение от mostApi Посмотреть сообщение
чтобы я знал на будущее?!
Читайте литературу по теме. Раз выбрали VB .Net, ищите хорошие книги, где и потоки разбираются.
0
Модератор
Эксперт .NET
4314 / 3388 / 507
Регистрация: 27.01.2014
Сообщений: 6,186
04.04.2017, 05:20 5
Из потока нельзя обращаться к GUI.
а как же делегаты? с ними то можно

Добавлено через 8 минут
кстати вот все тоже самое, что сказал Rius. Там и говорится что, при использовании потоков, для обращения к UI элементам, нужно использовать Invoke и делегаты... там кстати и пример есть про DataReceived
https://msdn.microsoft.com/ru-... .110).aspx
0
Эксперт .NET
11094 / 7013 / 1574
Регистрация: 25.05.2015
Сообщений: 21,176
Записей в блоге: 14
04.04.2017, 06:04 6
Цитата Сообщение от Yury Komar Посмотреть сообщение
там кстати и пример есть про DataReceived
Как я уже говорил, эта схема в общем случае не работает. SerialPort.Read гораздо пресказумее, но и у него есть недостатки. https://www.cyberforum.ru/blog... g4357.html
Сейчас допиливаю нативную C++ dll-ку с древними, но удобными методами WinAPI.
0
7 / 5 / 0
Регистрация: 15.05.2015
Сообщений: 350
04.04.2017, 10:54  [ТС] 7
Yury Komar, спасибо за ссылку, там пример консольного приложения...
У меня не первый случай необходимости создания потока, с него получить данные и отобразить их в главной форме программы, сколько примеров не находил так и не разобрался.(

Я так понимаю:
1. Form - это уже Class;
2. Если я выкидываю функцию или что иное в процесс, то эта функция должна быть в другом Class-e;
3. Для того чтобы с потока получить данные в Form мне нужно использовать Invoke и Delegate;
Может кто разжевать?!
0
Эксперт .NET
11094 / 7013 / 1574
Регистрация: 25.05.2015
Сообщений: 21,176
Записей в блоге: 14
04.04.2017, 12:15 8
1. Да.
2. Не обязательно.
3. Не обязательно, есть иные способы разной степени (±) костыльности.

Цитата Сообщение от mostApi Посмотреть сообщение
У меня не первый случай необходимости создания потока, с него получить данные и отобразить их в главной форме программы, сколько примеров не находил так и не разобрался.(
Литература по C# для начинающих и не только, Шилдт, 23-24 главы.
0
Модератор
Эксперт .NET
4314 / 3388 / 507
Регистрация: 27.01.2014
Сообщений: 6,186
04.04.2017, 14:39 9
Цитата Сообщение от mostApi Посмотреть сообщение
Может кто разжевать?!
самый простой способ, но не всегда помогает при запуске функции в потоке, которая пытается обратиться к элементам управления на форме

VB.NET
1
2
3
4
5
    Dim Поток_1 As New Threading.Thread(AddressOf МояФункция) 
    CheckForIllegalCrossThreadCalls = False
    Поток_1.SetApartmentState(Threading.ApartmentState.STA)
    Поток_1.IsBackground = True
    Поток_1.Start("Новый заголовок формы")
Делегат - структура данных, указывающая на статические методы или методы экземпляра класса в .NET Framework.
Подробнее можно почитать в Википедии. А на пальцах можно легко это показать:

Мы будем использовать делегат в качестве проводника между потоками и элементами управления формы, т.к по умолчанию к элементам управления можно получить доступ из того потока, в котором они были созданы, даже если проверка на "CheckForIllegalCrossThreadCalls" отключена, то иногда нельзя обратиться к контролам формы без помощи этих самых делегатов.

Поэтому покажу пример использования делегата(как приложение к нашей функции), который обеспечит другому потоку доступ к заголовку формы:
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'Объявляем делегат(всегда должени идти в паре с функцией), с такими же аргументами, как у нашей функции.
'Этот делегат поможет моей функции обращаться к контролам из отдельного потока.
Private Delegate Sub Deletage_Моей_Функции(ByVal АГРУМЕНТ As String) 
 
'Моя функция
Private Sub МояФункция(ByVal АГРУМЕНТ As String) 
    If Me.InvokeRequired Then 'Если запрос на запуск функции поступил из другого потока, то пускаем ее через делегат
        Me.Invoke(New Deletage_Моей_Функции(AddressOf МояФункция), АГРУМЕНТ)
    Else 'Если же запрос к функции был из родного потока (из формы), то просто выплоняем наш код
    '...
    '...
        Me.Text = АГРУМЕНТ  'Здесь пишем сам код нашей своей функции
    '...
    '...
    End If
End Sub
1
7 / 5 / 0
Регистрация: 15.05.2015
Сообщений: 350
07.04.2017, 20:44  [ТС] 10
Rius, Yury Komar, Rius, получилось, все работает как надо..., но...

В потоке в бесконечном цикле идет принятие информации с COM5 порта, пока он открыт. Принудительно завершаю поток - через 1 - 2 секунды программы вываливается в "The application is in break mode".
Как решить?

VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Imports System.Threading
Public Class Form1
    Private Delegate Sub d_getText(ByVal t As String)
    Private gData As New Thread(AddressOf GetData)
 
    Private Sub cb_start_Click(sender As Object, e As EventArgs) Handles cb_start.Click
        With SerialPort1
            .PortName = "COM5"
            .BaudRate = 9600
            .DataBits = 8
            .Parity = 0
            .StopBits = IO.Ports.StopBits.One
            .WriteTimeout = 2000
        End With
 
        If SerialPort1.IsOpen Then
            SerialPort1.RtsEnable = False
            SerialPort1.DtrEnable = False
            SerialPort1.Close()
        End If
 
        Try
            SerialPort1.Open()
        Catch ex As Exception
            tb1.Text = ex.Message : cb_start.Enabled = False
        End Try
 
        If SerialPort1.IsOpen Then
            gData.IsBackground = True ' Поток будет работать в фоновом режиме
            gData.Start()
        End If
    End Sub
 
    Private Function GetData()
        SerialPort1.RtsEnable = True
        While SerialPort1.IsOpen
            getText(SerialPort1.ReadLine)
        End While
        GetData = Nothing
    End Function
 
    Private Sub getText(ByVal t As String) ' Процедура делегата
        If tb1.InvokeRequired Then
            Me.Invoke(New d_getText(AddressOf getText), t) ' Если доступ из другого потока, то используем делегат
        Else ' Если запрос из родного (для элемента) потока, то просто записываем текст
            If tb1.Text.Length > 1 Then
                tb1.Text &= vbCrLf & t
            Else
                tb1.Text &= t
            End If
        End If
    End Sub
    Private Sub cb_stop_Click(sender As Object, e As EventArgs) Handles cb_stop.Click
        gData.Abort()
    End Sub
0
Эксперт .NET
11094 / 7013 / 1574
Регистрация: 25.05.2015
Сообщений: 21,176
Записей в блоге: 14
07.04.2017, 20:52 11
А вы завершайте аккуратно, а не через Abort.
1
7 / 5 / 0
Регистрация: 15.05.2015
Сообщений: 350
07.04.2017, 21:20  [ТС] 12
VB.NET
1
2
3
An unhandled exception of type 'System.ObjectDisposedException' occurred in mscorlib.dll
 
Additional information: Дескриптор SafeHandle был закрыт
Добавлено через 17 секунд
Rius, как?

Добавлено через 8 минут
Rius, в общем решил так:

1. Создал переменную типа Boolean = False;
2. Кнопка Стоп меняет ее состояние на = True;
3. Цикл в потоке сначала проверяет значение переменной, потом читает COM порт.
Если значение переменной True - выходит из цикла.

Так вроде работает без ошибки...
1
Модератор
Эксперт .NET
4314 / 3388 / 507
Регистрация: 27.01.2014
Сообщений: 6,186
08.04.2017, 18:31 13
Цитата Сообщение от mostApi Посмотреть сообщение
выходит из цикла.
правильно, нужно дать потоку дойти самому до конца своего кода, после чего он сам себя закроет, избегая тех ошибок, с которыми вы столкнулись выше...
2
08.04.2017, 18:31
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.04.2017, 18:31
Помогаю со студенческими работами здесь

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

Вынести соединение с БД в отдельный поток
Здравствуйте, уважаемые знатоки. Проблема у меня в следующем, есть программа для работы с БД mySQL,...

Вынести процедуру в отдельный поток
Доброго дня. Есть процедура, в процессе её работы происходит step прогрессбара, разумеется такие...

Вынести загрузку и парсинг в отдельный поток
Ребята,привет. Есть приложение,калькулятор и есть активность валюта,где конвертация валюты...

Вынести часть работы приложения в отдельный поток
Друзья, вот столкнулся с такой проблемой. У меня нормальный процессор, все программы быстро...

Вынести работу с сокетами в отдельный класс
Хочу вынести работу с сокетами в отдельный класс. В main.cpp все работает отлично. Но с классом...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru