Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.56/9: Рейтинг темы: голосов - 9, средняя оценка - 4.56
44 / 7 / 1
Регистрация: 05.08.2013
Сообщений: 60

Потоки и форма

27.09.2019, 13:21. Показов 2056. Ответов 23
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
C#
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
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Server
{
    public partial class Form1 : Form
    {
        private Thread thread;
        private bool start = true; // Флаг для выхода из цикла
        
        private void listener() //Потоковый метод
        {
            int count = 0;
 
            while (start)
            {
                count++;
 
                if (InvokeRequired) { //Инвок
                    Invoke(new Action(() =>
                    {
                        Log.Text += count.ToString() + "\r\n"; //Обращаемся к текстовому полю, что в основном потоке
                    }));
                }
            };             
 
           
        }
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void Form1_Load(object sender, EventArgs e) //Ставртуем поток в загрузке формы
        {
            thread = new Thread(listener); 
            thread.IsBackground = true;
            thread.Start();
        }        
 
        private void Form1_FormClosed(object sender, FormClosedEventArgs e) //Закрытие формы
        {
            start = false;
            if (thread.IsAlive) // Если поток жив, ликвидируем его.
            {
                thread.Abort();
            }
        }
 
     }

Вопрос такой.

Если я создам на форме кнопку, где буду менять флаг выхода из цикла, мне не нужно будет ликвидировать поток, цикл завершится и поток закроется сам. Но если я попытаюсь сделать, то же самое при закрытие выйдет ошибка - доступ к ликвидированному объекту Form1 запрещен.

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

Всем огромное спасибо.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
27.09.2019, 13:21
Ответы с готовыми решениями:

serialPort, форма и потоки
Допустим, на форме имеется label и к проекту прикручен стандртный компонент "serialPort" По приему байта пытаемся изменить текст...

Форма и потоки
Добрый день, всегда работал без интерфейсов, теперь перешёл на интерфейсы и столкнулся с вопросом как запустить поток, который при закрытии...

Добавление записи в Listview(1 форма) через Диалоговое окно(3 форма) другой формы (2 форма)
Всем доброго дня и с наступающими праздниками! Знаю, тема 7 частых вопросов по WinForms уже не раз обсуждалась, и была прочитана, но или...

23
44 / 7 / 1
Регистрация: 05.08.2013
Сообщений: 60
24.10.2019, 13:49  [ТС]
Студворк — интернет-сервис помощи студентам
Форму не подвешивает. Вообще чат работает, я тестил даже на инет сети. Белый айпи. Я хотел бы разобраться с потоками.
Сейчас вышлю исходник всего и вся.
Вложения
Тип файла: zip Saturn5.zip (999.4 Кб, 3 просмотров)
0
5 / 5 / 1
Регистрация: 30.09.2015
Сообщений: 17
26.10.2019, 20:44
Понятно.
Замечания.

1.
C#
1
2
3
4
5
6
7
8
9
10
11
        private void Connect(string ip)
        {
            try
            {
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);                
                 _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
                 _serverSocket.Connect(ipEndPoint);
                 ...
             }
         }
Операция Connect синхронно выполняется в главном потоке. Если при связи с сервером есть какие-то проблемы, форма висит в течении таймаута соединения. Это актуально для всех операций сокета. У Вас зависания незаметны из-за быстрого, почти мгновенного обмена с сервером.
Выходы:
а) использовать асинхронные операции вместо обычных. Изучайте async/await и пользуйтесь, например, ConnectAsync.
или
б) использовать Task, создавая паралельные потоки.

2.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            MessageBox.Show(e.CloseReason.ToString());
            if (_serverSocket != null  && _serverSocket.Connected == true)
            {
                e.Cancel = true;
                var bytes = Encoding.UTF8.GetBytes("<bye>" + Name);
                _serverSocket.Send(BitConverter.GetBytes(bytes.Length));
                _serverSocket.Send(Encoding.UTF8.GetBytes("<bye>" + Name));
                _serverSocket.Shutdown(SocketShutdown.Both);
                _serverSocket.Close();                
                start = false;
                MessageBox.Show(e.CloseReason.ToString());
            }
          
        }
Закрывает соединение! То есть, когда в паралельном потоке Вы вызываете _serverSocket.Receive или _serverSocket.Send, соединения может не существовать.
Выход:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            MessageBox.Show("Закрытие формы");
            if (start)
            {
                e.Cancel = true;
                MessageBox.Show("Отмена закрытия формы");
            }
        }
 
        private void Form1_FormClosed(object sender, FormClosingEventArgs e)
        {
            MessageBox.Show("Форма закрылась");
            if (_serverSocket != null  && _serverSocket.Connected == true)
            {
                var bytes = Encoding.UTF8.GetBytes("<bye>" + Name);
                _serverSocket.Send(BitConverter.GetBytes(bytes.Length));
                _serverSocket.Send(Encoding.UTF8.GetBytes("<bye>" + Name));
                _serverSocket.Shutdown(SocketShutdown.Both);
                _serverSocket.Close();                
                MessageBox.Show("Соединение закрылось");
            }       
        }
а) поменять условие на start.
И
б) перенести закрытие соединения в Form1_FormClosed
И
в) добавить таки Invoke(Close) в конец процедуры параллельного потока.

А так чат работает.
0
44 / 7 / 1
Регистрация: 05.08.2013
Сообщений: 60
28.10.2019, 15:58  [ТС]
DmitryB84,

Спасибо большое за помощь.

Не могу пока понять где должен быть start = false;

Делал

C#
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
 private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {           
            MessageBox.Show("Закрытие формы");
            if (start)
            {                
                start = false;
                e.Cancel = true;
                MessageBox.Show("Отмена закрытия формы");
            }
 
//и
 
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            MessageBox.Show("Форма закрылась");
            if (_serverSocket != null && _serverSocket.Connected == true)
            {
                var bytes = Encoding.UTF8.GetBytes("<bye>" + Name);
                _serverSocket.Send(BitConverter.GetBytes(bytes.Length));
                _serverSocket.Send(Encoding.UTF8.GetBytes("<bye>" + Name));*/
                _serverSocket.Shutdown(SocketShutdown.Both);
                _serverSocket.Close();
                MessageBox.Show("Соединение закрылось");
            }
        }
 
 
//А так же процедура слушателя, которая идет в параллельном потоке.
 
 
 private void listener() //Тут
        {
            //int length = 256;
            while (start)
            {
                MessageBox.Show("Привет");
                int length = 0;
                var size = 0;
                int recived = 0;
                var bt = new byte[4];
                do
                {
                    recived += _serverSocket.Receive(bt, recived, 4 - recived, SocketFlags.None);
 
                } while (recived < 4);
 
                length = BitConverter.ToInt32(bt, 0);                
                if (length > 0)
                {
                    try
                    {
                        MessageBox.Show(length.ToString());
                        var buffer = new byte[length];
                        size = 0;
                        var data = new StringBuilder();
                        do
                        {
                            size = _serverSocket.Receive(buffer);
                            data.Append(Encoding.UTF8.GetString(buffer, 0, size));
                        } while (_serverSocket.Available > 0);
 
                        //  MessageBox.Show("Вышел2");
 
                        if (InvokeRequired)
                        {
                            Invoke(new Action(() =>
                            {
                                if (data.ToString().Contains("<loader>"))
                                {
                                    var d = data.ToString().Remove(0, 8);
                                    users.Items.Clear();
                                    string[] names = d.Split('>');
                                    foreach (var name in names)
                                    {
                                        users.Items.Add(name);
                                    }
                                    var bytes = Encoding.UTF8.GetBytes("<shalom>");
                                    _serverSocket.Send(BitConverter.GetBytes(bytes.Length));
                                    _serverSocket.Send(bytes); //Тут                                                                                               
                                }
                                else /*if (data.ToString().Contains("<msg>"))*/
                                {
                                    Chat.Text = String.Empty;
                                    Chat.Text = data.ToString();
                                }
 
                            }));
                        }
 
                    }
                    catch (Exception ex)
                    {
                        if (InvokeRequired)
                        {
                            Invoke(new Action(() =>
                            {
                                Chat.Text = ex.Message;
                            }));
                        }
                    }
 
                }                      
            
            }
           
            Invoke(new Action(() =>
            {
                MessageBox.Show("543");
                Close();
            }));
        }

При первом нажатии на крестик программа не закрывается, срабатывает отмена закрытия формы.
При втором нажатии программа закрывается, но из цикла listener не выходит, сообщения MessageBox.Show("543"); не появляется.
0
44 / 7 / 1
Регистрация: 05.08.2013
Сообщений: 60
29.10.2019, 14:59  [ТС]
Сделал так:

1) При попытке закрытия формы, если установлено соединение с сервером, закрытие блокируется и
2) На сервер отсылается сигнал "bye".
3) Сервер принимает команду, отсылает всем клиентам, кроме прощающегося о том, что клиент ушел, а на простившийся клиент отсылает ответную "bye". После чего разрывает соединение с простившимся клиентом.
4) Получив команду bye, клиент ставит start в положение false, что провоцирует выход из цикла слушателя. Потом вызывается закрытие формы.
5) В закрытии формы, клиент разрывает соединение.

Верна ли логика? Вот код:

C#
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Client
{
    public partial class Form1 : Form
    {
        // private const string ip = "127.0.0.1";
        private bool start = true;
        private const int port = 8083;
        private Socket _serverSocket;
        private Thread thread;
 
        private void Send(Byte[] bytes)
        {
            _serverSocket.Send(BitConverter.GetBytes(bytes.Length));
            _serverSocket.Send(bytes);
        }
 
        private void Connect(string ip)
        {
            try
            {
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);                
                 _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);               
                 _serverSocket.Connect(ipEndPoint);
               
            }
            catch(Exception ex)
            {
                Chat.Text = ex.Message;               
            }
        }
 
        private void listener() //Тут
        {
            MessageBox.Show("h");
            //int length = 256;
            while (start)
            {
               // MessageBox.Show(start.ToString());
                int length = 0;
                var size = 0;
                int recived = 0;
                var bt = new byte[4];
                do
                {
                    recived += _serverSocket.Receive(bt, recived, 4 - recived, SocketFlags.None);
 
                } while (recived < 4);
 
                length = BitConverter.ToInt32(bt, 0);                
                if (length > 0)
                {
                    try
                    {
                        //MessageBox.Show(length.ToString());
                        var buffer = new byte[length];
                        size = 0;
                        var data = new StringBuilder();
                        do
                        {
                            size = _serverSocket.Receive(buffer);
                            data.Append(Encoding.UTF8.GetString(buffer, 0, size));
                        } while (_serverSocket.Available > 0);
 
                        //  MessageBox.Show("Вышел2");
 
                        if (InvokeRequired)
                        {
                            Invoke(new Action(() =>
                            {
                                if (data.ToString().Contains("<loader>"))
                                {
                                    var d = data.ToString().Remove(0, 8);
                                    users.Items.Clear();
                                    string[] names = d.Split('>');
                                    foreach (var name in names)
                                    {
                                        users.Items.Add(name);
                                    }
                                    var bytes = Encoding.UTF8.GetBytes("<shalom>");
                                    //Тут*/
                                    Send(bytes);
                                }
                                else if (data.ToString() == "<bye>")
                                {
                                    start = false;                                  
                                }
                                else
                                {
                                    Chat.Text = String.Empty;
                                    Chat.Text = data.ToString(); 
                                }
 
                            }));
                        }
 
                    }
                    catch (Exception ex)
                    {
                        if (InvokeRequired)
                        {
                            Invoke(new Action(() =>
                            {
                                Chat.Text = ex.Message;
                            }));
                        }
                    }
 
                }                      
            
            }
           
           // Invoke(new Action(() =>
           // {
                MessageBox.Show("Выход из цикла");
                Close();
          //  }));
        }
        public Form1()
        {
            InitializeComponent();
        }
 
       
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            
 
           
            if (start)
            {
                MessageBox.Show("Попытка закрытия формы");
                if (_serverSocket != null && _serverSocket.Connected)
                {
                    e.Cancel = true;
                    MessageBox.Show("Отмена закрытия формы");
                    var bytes = Encoding.UTF8.GetBytes("<bye>" + Name);
                    Send(bytes);
                }
            }
 
 
        }
 
        private void btnMessage_Click(object sender, EventArgs e)
        {
             var bytes = Encoding.UTF8.GetBytes(Name + " пишет: " + txtMessage.Text);
            Send(bytes);
            txtMessage.Text = String.Empty;
            txtMessage.Focus();              
        }
 
        private void btnName_Click(object sender, EventArgs e)
        {
            Name = txtName.Text;
            Connect(txtIp.Text);
            if (_serverSocket != null &&  _serverSocket.Connected) {
                btnName.Enabled = false;
                txtName.Enabled = false;
                txtIp.Enabled = false;                
                txtMessage.Enabled = true;               
                thread = new Thread(listener);
                thread.IsBackground = true;
                thread.Start();                
                var bytes = Encoding.UTF8.GetBytes("<setname>" + txtName.Text);
                Send(bytes);               
                txtMessage.Focus();
            }
        }
 
        private void txtMessage_TextChanged(object sender, EventArgs e)
        {
            btnMessage.Enabled = !String.IsNullOrWhiteSpace(((TextBox)sender).Text);
        }
 
        private void txtName_TextChanged(object sender, EventArgs e)
        {
            btnName.Enabled = !String.IsNullOrWhiteSpace(((TextBox)sender).Text);
        }
 
       
 
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
           
            if (_serverSocket != null && _serverSocket.Connected == true)
            {               
                _serverSocket.Shutdown(SocketShutdown.Both);
                _serverSocket.Close();
                MessageBox.Show("Соединение закрылось");
            }
            MessageBox.Show("Форма закрылась");
        }
    }
}
Добавлено через 1 час 20 минут

Добавлено через 4 часа 12 минут
Почему-то когда, я закрываю сервер, если к нему были подключены клиенты, их формы закрываются. В предыдущем коде тоже так было.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
29.10.2019, 14:59

Форма 1 вызывает форму 2, форма 2 закрывается, форма 1 продолжает работать дальше
Вынес предстартовые действия формы1 в форму2 (там у меня проверка существования файлов, их закачка если нету и проверка обновления), но как...

Что такое потоки ввода, потоки вывода?
Здарова всем! Не так давно уже прогаю на С++ и все НИКАК не могу понять, что такое потоки ввода, потоки вывода..! вот допустим...

Байтовые потоки и потоки символов
Объясните, пожалуйста подробно что имелось ввиду На самом низком уровне все операции ввода/вывода в С# оперируют байтами. Подобный...

Не закрывается форма 1, а после вызова формы 2, форма 1 дублируется несколько раз
имеется форма, на ней кнопка. нажимаю и открывается новая форма, но старая снова появляется неограниченное количество раз код 1...

Форма авторизации - вне зависимости от выбранного пользака, открывается одна и та же форма
Форма авторизации - вне зависимости от выбранного пользака, открывается одна и та же форма Есть два пользака - главбух и ведущий бух В...


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

Или воспользуйтесь поиском по форуму:
24
Ответ Создать тему
Новые блоги и статьи
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru