Страницы

Поиск по вопросам

воскресенье, 29 декабря 2019 г.

Прерывание потока с вечным циклом

#c_sharp #windows #многопоточность


Мне необходимо во время работы утилиты все время слушать порт, и когда на него поступают
команды, выполнять определенные действия. Сама утилита у меня реализована в виде формы
 WinForms, а при ее старте вызывается отдельный поток с вечным циклом. Выглядит все
примерно так

ServThread = new Thread(new ThreadStart(ServStart));
ServThread.IsBackground = true;
ServThread.Start();


и далее уже в этом потоке

Listener = new TcpListener(LocalPort);
Listener.Start();
while (true)
{
    TcpClient client = Listener.AcceptTcpClient();
    //что-то делаем...
} //завершили итерацию


Проблема вот в чем - если выходить из системы (win7, xp), то просит принудительно
завершить программу http://joxi.ru/ZrJE6y8t8lQgAj. По-видимому, из-за вечного цикла.
Как можно решить эту проблему?
    


Ответы

Ответ 1



Попробуйте асинхронный интерфейс. async Task AcceptAsync(TcpListener listener, CancellationToken ct) { using (ct.Register(listener.Stop)) { try { return await listener.AcceptTcpClientAsync(); } catch (SocketException e) { if (e.SocketErrorCode == SocketError.Interrupted) throw new OperationCanceledExeption(); throw; } } } Теперь вам не нужен отдельный поток, и вы можете писать так: m_cts = new CancellationTokenSource(); try { var listener = new TcpListener(LocalPort); listener.Start(); while (true) { TcpClient client = await AcceptAsync(listener, m_cts.Token); //что-то делаем... } } catch (OperationCanceledException) { // операция оборвана } и разумеется void StopListener() { m_cts.Cancel(); } При завершении программы не забудьте вызвать StopListener.

Ответ 2



Можно попробовать сделать Listener объектом доступным из основного (UI) thread. Когда форма закрывается - вызвать Listener.Server.Close()

Ответ 3



Более простой вариант "в лоб". В конце вечного цикла ставить Thread.Sleep(0): while (true) { do_some_job(); //Allow other thread to work Thread.Sleep(0); }

Ответ 4



сделал отдельным классом: class ServiceWorker { public TcpListener Listener; // Объект, принимающий TCP-клиентов // Thread signal. public ManualResetEvent tcpClientConnected; public ServiceWorker() { _shouldStop = false; tcpClientConnected = new ManualResetEvent(false); // Создаем "слушателя" для указанного порта Listener = new TcpListener(IPAddress.Any, 6543); } public void ThreadProc() { Listener.Start(); // Запускаем его // В бесконечном цикле while (!_shouldStop) { // Принимаем новых клиентов tcpClientConnected.Reset(); // Accept the connection. // BeginAcceptSocket() creates the accepted socket. Listener.BeginAcceptTcpClient( new AsyncCallback(DoAcceptTcpClientCallback), this); tcpClientConnected.WaitOne(); } // Остановим "слушателя" Listener.Stop(); } // Process the client connection. public static void DoAcceptTcpClientCallback(IAsyncResult ar) { // Get the listener that handles the client request. ServiceWorker worker = (ServiceWorker)ar.AsyncState; Socket client = worker.Listener.EndAcceptSocket(ar); Client(client); // Signal the calling thread to continue. worker.tcpClientConnected.Set(); } public void RequestStop() { _shouldStop = true; tcpClientConnected.Set(); } private volatile bool _shouldStop; } управление запуск: private ServiceWorker worker = new ServiceWorker(); Thread t = new Thread(worker.ThreadProc); t.Start(); остановка: worker.RequestStop();

Комментариев нет:

Отправить комментарий