Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/11: Рейтинг темы: голосов - 11, средняя оценка - 5.00
1 / 1 / 0
Регистрация: 20.04.2017
Сообщений: 68

Передача данных между двумя потоками

13.06.2021, 20:34. Показов 2084. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте.

Необходимо реализовать программу, которая записывает данные в файл пришедшие по UDP со скоростью 1G.
В будущем планируется с 4 розеток принимать данные.
Я написал программу классы прикладываю к вопросу:
Класс UDPHandler принимает данные и возвращает через событие
Класс TOP_file. В нем подписываемся на событие UDPHandler и принимаем данные, после чего отправляем в третий поток эти данные т.е. в класс Writerln_FILE в котором записываем данные.

Так вот, данные принимаются, а когда данные повторно пытаются отправиться в поток в котором происходит запись, вылетает исключение Исключение вида System.Threading.ThreadStateException: Thread is running or terminated; it cannot restart.
at System.Threading.Thread.StartupSetApartm entStateInternal()
at System.Threading.Thread.Start()
at System.Threading.Thread.Start(Object parameter)

Типо поток запущен либо остановлен.

Исключение возникает тут:

C#
1
2
3
4
5
6
7
8
9
 private void UDPhandler_DataRecive(byte[] vs)
        {
            try
            {
               if(thread_WR.IsAlive) thread_WR.Join();
               else thread_WR.Start((object)vs);
            }
            catch(Exception e) { Console.WriteLine($"Исключение вида {e}"); }
        }
Класс TOP_file
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
using LookSin;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading;
 
namespace Recive_data_from_ADC
{
    class TOP_file
    {
        /// <summary>
        /// Порт для прослушивания
        /// </summary>
        private static uint NumPort;
        public static uint numPort { get { return NumPort; } private set { } }
 
 
 
 
        /// <summary>
        /// Путь к катологу для прослушивания
        /// </summary>
        private static string path_to_catolog_for_file;
        public static string Path_to_catolog_for_file { get { return path_to_catolog_for_file; } private set { } }
 
 
 
        /// <summary>
        /// ip адрес отправителя
        /// </summary>
        private static IPAddress iPAddress;
        public static IPAddress IPAdd_ { get { return iPAddress; } private set { } }
 
        public static UDHHandler UDPhandler;
 
        public static WriterIn_FILE WR_File;
 
 
        Thread thread_WR;
        Thread thread_UDP;
 
        public TOP_file(string path_to_catolog_for_file, IPAddress iPAddress, uint NumPort)
        {
 
            ////////////////////////////////////////////////////////////////
            UDPhandler = new UDHHandler(NumPort, iPAddress);
            UDPhandler.DataRecive += UDPhandler_DataRecive;
 
            ////////////////////////////////////////////////////////////////
            WR_File = new WriterIn_FILE(NumPort, path_to_catolog_for_file);
            TOP_file.NumPort = NumPort;
            TOP_file.path_to_catolog_for_file = path_to_catolog_for_file;
            TOP_file.iPAddress = iPAddress;
 
            ///Создаем поток для работы с записью в файл
            thread_WR = new Thread(new ParameterizedThreadStart(WR_File.WriterInFILE));
 
            ///Создаем поток для работы с UDP
            thread_UDP = new Thread(new ThreadStart(UDPhandler.UDPRecive));
 
        }
 
 
 
 
 
 
        private void UDPhandler_DataRecive(byte[] vs)
        {
            try
            {
               if(thread_WR.IsAlive) thread_WR.Join();
               else thread_WR.Start((object)vs);
            }
            catch(Exception e) { Console.WriteLine($"Исключение вида {e}"); }
        }
 
        public void StartRecive()
        {
            thread_UDP.Start();
        }
 
        /// <summary>
        /// Метод полностью завершает выполнение потоков приема и записи данных
        /// </summary>
        public void Stop()
        {
            UDPhandler.UDPClose();
            thread_WR.Abort();
            thread_WR.Join();
            thread_UDP.Abort();
            thread_UDP.Join();
        }
    }
}
Класс WriterIn_FILE
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
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
 
namespace Recive_data_from_ADC
{
    /// <summary>
    /// Класс для записи данных в бинарный файл 
    /// </summary>
    public class WriterIn_FILE
    {
        /// <summary>
        /// Делегат для события которое говорит об возникших проблемах или исключении
        /// </summary>
        /// <param name="str"></param>
        public delegate void DelegateForString(string str);
 
        /// <summary>
        /// Событие возвращающее сообщение
        /// </summary>
        public event DelegateForString Message;
 
        /// <summary>
        /// Событие возвращающее возникшее исклчение
        /// </summary>
        public static event DelegateForString Exep_;
 
 
 
        /// <summary>
        /// Начальное имя файл, изменяет в тот момент когда в предыдущем файле размер превысил 1 Гбайт
        /// </summary>
        public string Start_Name_file { get; private set; }
 
        /// <summary>
        /// Приемный порт, в данном классе выступает в роле идентефикатора для файла, в который пишутся данные с определенного порта
        /// По желанию можно любое число от 0 до 4294967295
        /// </summary>
        public uint receiving_port { get; private set; }
        
        /// <summary>
        /// Путь к катологу где лежит файл
        /// </summary>
        public string path_to_catolog_for_file { get; private set; }
 
 
 
 
        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="receiving_port">Приемный порт, в данном классе выступает в роле идентефикатора для файла, в который пишутся данные с определенного порта
        /// По желанию можно любое число от 0 до 4294967295</param>
        /// <param name="path_to_catolog_for_file">Путь к катологу где лежит файл</param>
        public WriterIn_FILE(uint receiving_port, string path_to_catolog_for_file)
        {
            //Создаем экземпляр класса для проверки наличия данной директории
            System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(path_to_catolog_for_file);
            
            //Проверяем существует ли такая директория 
            //Если нет, то создаем ее, если она существует создаем файл согодняшних измерений
            if (!dirInfo.Exists)
            {
                Console.WriteLine("Директория не существует, и будет создана");
                //Message?.Invoke("Директория не существует, и будет создана");
                try
                {
                    dirInfo.Create();
                    Console.WriteLine("Директория cоздана");
                    //Message?.Invoke("Директория cоздана");
                }
                catch (Exception e) 
                {
                    Console.WriteLine($"Возникло исключение вида {e}");
                    //Exep_?.Invoke($"Возникло исключение вида {e}"); 
                }
            }
 
            ///Создаем начальное имя файла из даты, времени и года плюс порт просушиввания
            ///Имя файла будет изменяться со врменем когда размер файла будет превышать 1Гбайт, будет 
            ///создаваться новый файл с дополнительным префиксом _1,_2...
 
            string dateTime = DateTime.Now.ToString();
            dateTime = dateTime.Replace(":", ".");
            Start_Name_file = dateTime + $" Порт прослушивания {receiving_port}.txt";
 
            this.receiving_port = receiving_port;
 
            this.path_to_catolog_for_file = path_to_catolog_for_file;
 
            //Создаем папку в директории для записи измерений производимых сегодня.
            try
            {
                using (File.Create($@"{path_to_catolog_for_file}\{Start_Name_file}")) { }
                Console.WriteLine("Файл создан");
                //Message?.Invoke("Файл создан");
            }
            catch(Exception e) 
            {
                Console.WriteLine($"Возникло исключение вида {e}");
                //Exep_?.Invoke($"Возникло исключение вида {e}"); 
            }
 
        }
 
        /// <summary>
        /// Счетчик файлов 
        /// </summary>
        private static int count;
        public static int Count_file { get { return count; } private set { count = 1; } }
 
 
        /// <summary>
        /// Метод для записи данных в файл, также производит проверку файла и если рамер файла превышает 1гбайт, создает новый файл с префиксом _2
        /// </summary>
        /// <param name="date">Данные, типо object был выдран для того, чтобы можно было передавать данные в поток</param>
        public void WriterInFILE(object date)
        {
            byte[] vs = (byte[])date;
            try
            {
                //Проверяем длину файла
                //Запись в файл будем осуществлять по 1 Гбайту
                FileInfo fileInfo = new FileInfo($@"{path_to_catolog_for_file}\{Start_Name_file}");
                if(fileInfo.Length != 1073741824) 
                {
                    //Если файл размером меньше чем 1 Гбайт, то записываем данные
                    using(FileStream fileStream = new FileStream($@"{path_to_catolog_for_file}\{Start_Name_file}", FileMode.OpenOrCreate))
                    {
                        fileStream.Write(vs);
                    }
                }
                else
                {
                    count++;
                    //Если длина файла превысила размер 1 Гбайт, то создаем новый файл с префиксом 2
                    //Переписываем переменную Start_Name_file и начинаем запись 
                    File.Create($@"{path_to_catolog_for_file}\{Start_Name_file}_{count}");
                    Start_Name_file = @$"{Start_Name_file}_{count}";
                    using (FileStream fileStream = new FileStream($@"{path_to_catolog_for_file}\{Start_Name_file}", FileMode.OpenOrCreate))
                    {
                        fileStream.Write(vs);
                    }
                }
            }
            catch (Exception e) 
            {
                Console.WriteLine($"Возникло исключение вида {e}\r\n");
                //Exep_?.Invoke($"Возникло исключение вида {e}\r\n" +
                //$"Возможные ошибки:\r\n" +
                //$"-Файл был удален\r\n" +
                //$"-Запись в файл невозможна\r\n" +
                //$"-Возникло исключение при создании файла"); 
            }
 
        }
    }
}
Класс UDHHandler

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
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
 
namespace LookSin
{
    class UDHHandler
    {
        private bool FlagStorResive = false;
 
        /// <summary>
        /// Делегат для события возвращаюего полученные данные из UDP
        /// </summary>
        /// <param name="vs"></param>
        public delegate void UDHHandDelegat(byte[] vs);
 
        /// <summary>
        /// Делегат для создания события, которое возвращает исключения
        /// </summary>
        public event UDHHandDelegat DataRecive;
 
 
        /// <summary>
        /// Событие возвращающее исключение
        /// </summary>
        /// <param name="str"></param>
        public delegate void UDPHandlerExeption(string str);
 
        /// <summary>
        /// Событие возвращающее принятые данные
        /// </summary>
        public event UDPHandlerExeption Exep;
 
        
        /// <summary>
        /// Номер порта прослушивания
        /// </summary>
        public UInt16 NumPort { get; private set; }
        
 
        /// <summary>
        /// ip адрес отправителя
        /// </summary>
        public IPAddress iPAddres { get; private set; }
 
 
        private UdpClient udpClient;
 
 
        private IPEndPoint RemoteIpEndPoint = null;
 
        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="NumPort">Принимает прослушиваемый порт</param>
        /// <param name="iPAddres">ip адрес отправителя</param>
        public UDHHandler(uint NumPort, IPAddress iPAddres) 
        {
            this.iPAddres = iPAddres;
            this.NumPort = (ushort)NumPort;
            udpClient = new UdpClient((ushort)NumPort);
            RemoteIpEndPoint = new IPEndPoint(iPAddres, (ushort)NumPort);
        }
 
 
 
        public void UDPRecive() 
        {
            try
            {
                while (FlagStorResive == false)
                {
                    byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
                    Console.WriteLine(receiveBytes.ToString());
                    DataRecive?.Invoke(receiveBytes);
                }
            }
            catch(Exception e)
            {
                Console.WriteLine($"Произошло исключение в блоке UDPRecive, вида {e} ");
                //Exep?.Invoke($"Произошло исключение в блоке UDPRecive, вида {e} \r\n" +
                //    $"----> Метод приема закрыт, для возобновления необходимо вызвать заново метод UDPRecive();");
                return;
            }
        }
 
        public void UDPClose() 
        {
            FlagStorResive = true;
            udpClient.Close();
        }
 
 
 
 
    }
}

Класс Program

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
using LookSin;
using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices;
 
namespace Recive_data_from_ADC
{
    class Program
    {
        static bool exitSystem = false;
        static TOP_file tOP_File_2;
        static TOP_file tOP_File;
 
 
 
        #region Trap application termination
        [DllImport("Kernel32")]
        private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
 
        private delegate bool EventHandler(CtrlType sig);
        static EventHandler _handler;
 
        enum CtrlType
        {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT = 1,
            CTRL_CLOSE_EVENT = 2,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT = 6
        }
 
        private static bool Handler(CtrlType sig)
        {
            Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown");
 
 
 
 
 
            ////do your cleanup here
            //System.Threading.Thread.Sleep(5000); //simulate some cleanup delay
 
            //Console.WriteLine("Cleanup complete");
 
            ////allow main to run off
            //exitSystem = true;
 
            ////shutdown right away so there are no lingering threads
            Environment.Exit(-1);
 
            return true;
        }
        #endregion
 
 
        static void Main(string[] args)
        {
            // Some biolerplate to react to close window event, CTRL-C, kill, etc
            _handler += new EventHandler(Handler);
            SetConsoleCtrlHandler(_handler, true);
 
 
 
            byte[] ip = {192,168,0,57};
            IPAddress iPAddres = new IPAddress(ip);
            tOP_File = new TOP_file($@"C:\Users\Nikita\Desktop\LOL", iPAddres, 1400);
            Console.WriteLine("Запись с порта 1400 начата");
            tOP_File.StartRecive();
 
 
            tOP_File_2 = new TOP_file($@"C:\Users\Nikita\Desktop\LOL", iPAddres, 2500);
            tOP_File_2.StartRecive();
            Console.WriteLine("Запись с порта 2500 начата");
            
        }
 
    }
}

Большое спасибо за помощь!!!!

Добавлено через 1 час 23 минуты
Цитата Сообщение от NiKit_A Посмотреть сообщение
Исключение возникает тут:

 private void UDPhandler_DataRecive(byte[] vs)
        {
            try
            {
               if(thread_WR.IsAlive) thread_WR.Join();
               else thread_WR.Start((object)vs);
            }
            catch(Exception e) { Console.WriteLine($"Исключение вида {e}"); }
        }


Я понял почему возникает исключение, потому что поток отработал свое в классе WriterIn_FILE метод WriterInFILE.
Тогда как можно поступить, чтобы запись осуществлялась постоянно? Точнее данные пришли, после этого передались во второй поток (в это время данные идет и иду) который начал запись и все по кругу.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
13.06.2021, 20:34
Ответы с готовыми решениями:

Передача сообщений между потоками
Привет! Есть у меня простой класс-логгер: static class Logger { public delegate void Message(string msg); ...

Передача данных на удаленный сервер по TCP несколькими потоками
День добрый! Подскажите как лучше сделать, нкжно передавать данные на удалённый сервер по TCP, в один поток всё работает, вопрос как...

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

4
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
13.06.2021, 20:39
Цитата Сообщение от NiKit_A Посмотреть сообщение
Тогда как можно поступить, чтобы запись осуществлялась постоянно?
Избавиться от потока, предназначенного для записи в файл. И писать сразу при получении в методе UDPhandler_DataRecive.
Либо писать не сразу, а аккумулировать в буфер до нужного размера, а потом уже писать в файл.
0
1 / 1 / 0
Регистрация: 20.04.2017
Сообщений: 68
13.06.2021, 20:44  [ТС]
Цитата Сообщение от IamRain Посмотреть сообщение
Избавиться от потока, предназначенного для записи в файл. И писать сразу при получении в методе UDPhandler_DataRecive.
Либо писать не сразу, а аккумулировать в буфер до нужного размера, а потом уже писать в файл.
Большое спасибо за ответ!
Я бы хотел уточнить, если данные будут идти на скорости 1G (если точнее скорость составляет 990912000 бит/c), я успею записать и потом опять принять данные?
0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
13.06.2021, 21:05
В сетевой подсистеме ОС все равно имеется буфер для полученных данных, и насколько я знаю, вы будете получать данные из этого буфера. То есть потерь быть не должно.
Ну я бы экспериментировал, пробовал бы писать асинхронно, если потери все же будут.
1
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
17.06.2021, 23:34
Цитата Сообщение от NiKit_A Посмотреть сообщение
если данные будут идти на скорости 1G (если точнее скорость составляет 990912000 бит/c), я успею записать и потом опять принять данные?
Даже если нет, то отдельный поток никак не ускорит запись. Максимум чего удасться достичь это очередь записи ограниченная обьемом доступной оперативной памяти.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.06.2021, 23:34
Помогаю со студенческими работами здесь

Передача данных между двумя формами
Здравствуйте. Подскажите пожалуйста, как грамотно передавать данные.. Есть две формы. На первой с использованием разных форм, формул...

Передача данных между двумя ViewModel
Задача типовая: есть главное окно, отображающее некий список. Пусть это будут фамилии студентов. После выбора студента и клика по кнопке...

Передача данных между двумя страницами
У меня есть страница со списком фильмов (название, год, жанр) и есть кнопка &quot;Добавить&quot; Когда я на нее нажимаю - появляется вторая...

Передача данных между двумя страницами
Доброго времени суток. Подскажите знатоки. Что-то я никак не могу понять, как мне отобразить данные на второй странице. Это код под вин...

Передача данных между двумя формами
Здравствуйте ,у меня есть две формы ,на одной я меняю положение трекбара ,и нужно что бы эти значения передовались в вторую форму (в ее...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
Программный отбор значений справочника
Maks 21.03.2026
Установка программного отбора значений справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит предопределенное значение перечислений. Процедура. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru