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

Правильно завершить поток

07.03.2016, 12:08. Показов 8683. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Прошу помощи людей, хорошо разбирающихся в многопоточности. Из-за зависания формы приложения во время долгого выполнения (не отвечают никакие элементы управления) пришёл к воплощению многопоточности в дело. Но если делегаты и потоки удалось освоить, то правильно завершить эти потоки никак не удаётся. К сожалению во всей литературе и на форумах не нашёл ответа на этот вопрос, везде речь о создании потока, а не о завершении во время его выполнения. Привожу сильно упрощённый вариант, где в качестве комментарий заключены различные попытки завершения потока. Одна кнопка запускает поток, другая его должна завершать. Вот как это воплотить?

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
56
57
58
59
60
61
62
Imports System.Threading
Imports System.IO
 
Public Class Form1
    Inherits System.Windows.Forms.Form
    Public Delegate Sub ДелегатТекст(ByVal text As String)
    Public Delegate Sub ДелегатЦифр(ByVal text As Integer)
 
    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Button1.Text = "Старт"
        Button2.Text = "Стоп"
    End Sub
 
    ' Делегат 1
    Private Sub ListBox(s As String)
        If ListBox1.InvokeRequired Then
            Me.Invoke(New ДелегатТекст(AddressOf ListBox), s)
        Else
            ListBox1.Items.Add(s)
        End If
    End Sub
 
    ' Делегат 2
    Private Sub Label(s As Integer)
        If Label1.InvokeRequired Then
            Me.Invoke(New ДелегатЦифр(AddressOf Label), s)
        Else
            Label1.Refresh()
            Label1.Text = s
        End If
    End Sub
 
    ' Процесс потока
    Public Sub Процесс_потока(ByVal ИменаФайлов As System.Object) ' Процесс потока
        For a = 0 To 100000
            Label(a)
            ListBox(a)
        Next
    End Sub
 
    'Запуск потока
    Public Sub Кнопка_Старт(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim Поток As New System.Threading.Thread(AddressOf Процесс_потока)
        'Поток.IsBackground = True
        Поток.Start()
    End Sub
 
    'Остановка потока
    Public Sub Кнопка_Стоп(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        'Поток.Abort()
        'Me.Refresh()
    End Sub
 
    'Private Sub Закрытие(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
    '    'Поток.Abort()
    '    e.Cancel = True
    '    sender.hide()
    '    Me.Finalize()
    '    Me.Dispose()
    '    Me.Close()
    'End Sub
End Class
Буду рад любым советам, хотя различнейшие варианты уже перепробовал...
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.03.2016, 12:08
Ответы с готовыми решениями:

Visual Studio 2013 - Как правильно завершить проект и создать install со своим значком
Подскажите пожалуйста, как правильно поступить при завершении проекта. То есть получается после VS...

Правильно завершить поток
Здравствуйте!!! Делаю программу через поток. Вот код #include <vcl.h> #pragma hdrstop ...

Как правильно завершить поток
Всем привет. Что я делаю не так ? Поток запускается и работает хорошо, но вот при завершении...

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

20
172 / 180 / 27
Регистрация: 26.11.2011
Сообщений: 386
Записей в блоге: 1
07.03.2016, 13:45 2
При работе с потоками у меня сложилось мнение что правильно его закрыть можно только выгрузкой приложения.
1
2 / 2 / 2
Регистрация: 22.04.2014
Сообщений: 18
07.03.2016, 14:09 3
Создать переменную, кнопкой стоп присваивать значение, в потоке в цикле проверять переменную, при значении присвоеном кнопкой стоп, выходить из процесса
0
Эксперт .NET
10575 / 6499 / 1506
Регистрация: 25.05.2015
Сообщений: 19,692
Записей в блоге: 14
07.03.2016, 14:11 4
dymitri, всё просто.
Есть некий булевый флаг. Флаг установлен в одно положение при старте потока. Устанавливается в другое положение при необходимости завершения потока.
В функции. выполняющейся в потоке, идёт периодическая проверка этого флага. Если флаг перешёл в состояние "остановить поток", производится возврат из функции потока.
Всё.

Ещё у Task из .Net >= 4.0 есть возможность использования CancellationToken.
1
0 / 0 / 0
Регистрация: 16.01.2016
Сообщений: 49
07.03.2016, 22:15  [ТС] 5
foxkid, В цикле потока невозможно завершить этот поток, т.к. объявлен и создан он в другой процедуре. Выход же из процедуры не завершает поток! Поэтому и просил совета у ЗНАЮЩИХ эту тему.

Rius, спасибо. Очень интересно было бы увидеть хоть какой-то пример. Если "всё просто", то очень прошу вас подсказать, как бы это осуществить в данном выше упрощённом коде, а я уже додумаю в реальном приложении.
0
Эксперт .NET
10575 / 6499 / 1506
Регистрация: 25.05.2015
Сообщений: 19,692
Записей в блоге: 14
07.03.2016, 23:12 6
dymitri, так всё же в справке есть, её для того и пишут.
https://msdn.microsoft.com/ru-... 10%29.aspx
0
0 / 0 / 0
Регистрация: 16.01.2016
Сообщений: 49
08.03.2016, 09:10  [ТС] 7
Rius, написанную справку смотрел, но практически ничего не понял, т.к. описание примера на английском. А совета я просил именно по конкретному примеру, а не абстрактно о всём классе. Ссылки на справки могу давать не хуже вас.

GSXL, у меня та же проблема. Даже после закрытия приложения, процесс висит. Наслышан вообще о проблеме правильной выгрузки приложения вместе со всеми процессами. И соответственно, как в приведённом примере правильно закрыть приложение, что бы процесс тоже завершался?
0
Эксперт .NET
10575 / 6499 / 1506
Регистрация: 25.05.2015
Сообщений: 19,692
Записей в блоге: 14
08.03.2016, 09:50 8
dymitri, Выжпрограммист, не? С таким подходом далеко не уедете.

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
56
57
58
59
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Windows.Forms
 
Namespace dymitri
    Public Partial Class Form1
        Inherits Form
        Private mToken As CancellationTokenSource
        Private mContextUI As TaskScheduler
        Private mTask As Task
 
        Public Sub New()
            InitializeComponent()
            Me.mContextUI = TaskScheduler.FromCurrentSynchronizationContext()
            Me.mToken = New CancellationTokenSource()
            Me.mTask = Task.Factory.StartNew(AddressOf Me.Method, Me.mToken.Token, Me.mToken.Token)
        End Sub
 
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs)
            Try
                Me.mToken.Cancel()
                Me.mTask.Wait()
            Catch exc As AggregateException
                        ' Task cancelled
                If Me.mTask.IsCanceled Then
                End If
            End Try
        End Sub
 
        Private Sub Method(ct As Object)
            Dim token As CancellationToken = DirectCast(ct, CancellationToken)
 
            While True
                Thread.Sleep(100)
 
                token.ThrowIfCancellationRequested()
 
                Task.Factory.StartNew(Function() InlineAssignHelper(Me.Text, DateTime.Now.ToString()), CancellationToken.None, TaskCreationOptions.None, Me.mContextUI)
            End While
        End Sub
        Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
            target = value
            Return value
        End Function
    End Class
End Namespace
 
'=======================================================
'Service provided by Telerik ([url]www.telerik.com[/url])
'Conversion powered by NRefactory.
'Twitter: @telerik
'Facebook: facebook.com/telerik
'=======================================================
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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace dymitri
{
    public partial class Form1 : Form
    {
        private CancellationTokenSource mToken;
        private TaskScheduler mContextUI;
        private Task mTask;
 
        public Form1()
        {
            InitializeComponent();
            this.mContextUI = TaskScheduler.FromCurrentSynchronizationContext();
            this.mToken = new CancellationTokenSource();
            this.mTask = Task.Factory.StartNew(this.Method, this.mToken.Token, this.mToken.Token);
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                this.mToken.Cancel();
                this.mTask.Wait();
            }
            catch (AggregateException exc)
            {
                if (this.mTask.IsCanceled)
                {
                    // Task cancelled
                }
            }
        }
 
        private void Method(object ct)
        {
            CancellationToken token = (CancellationToken)ct;
 
            while (true)
            {
                Thread.Sleep(100);
 
                token.ThrowIfCancellationRequested();
 
                Task.Factory.StartNew(() => this.Text = DateTime.Now.ToString(), CancellationToken.None, TaskCreationOptions.None, this.mContextUI);
            }
        }
    }
}
1
144 / 132 / 34
Регистрация: 28.02.2014
Сообщений: 159
08.03.2016, 11:05 9
Можно сделать так как сказал Rius:
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
    Public Delegate Sub ДелегатТекст(ByVal text As String)
    Public Delegate Sub ДелегатЦифр(ByVal text As Integer)
    Public ext As Boolean = False
 
    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Button1.Text = "Старт"
        Button2.Text = "Стоп"
    End Sub
 
    ' Делегат 1
    Private Sub ListBox(s As String)
        If ListBox1.InvokeRequired Then
            Me.Invoke(New ДелегатТекст(AddressOf ListBox), s)
        Else
            ListBox1.Items.Add(s)
        End If
    End Sub
 
    ' Делегат 2
    Private Sub Label(s As Integer)
        If Label1.InvokeRequired Then
            Me.Invoke(New ДелегатЦифр(AddressOf Label), s)
        Else
            Label1.Refresh()
            Label1.Text = s
        End If
    End Sub
 
    ' Процесс потока
    Public Sub Процесс_потока(ByVal ИменаФайлов As System.Object) ' Процесс потока
        For a = 0 To 100000
                Label(a)
                ListBox(a)
            If ext Then Exit For
        Next
    End Sub
 
    'Запуск потока
    Public Sub Кнопка_Старт(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim Поток As New System.Threading.Thread(AddressOf Процесс_потока)
        Поток.Start()
    End Sub
 
    'Остановка потока
    Public Sub Кнопка_Стоп(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        ext = True
    End Sub
1
0 / 0 / 0
Регистрация: 16.01.2016
Сообщений: 49
08.03.2016, 16:43  [ТС] 10
vova2112, Спасибо огромное! Пока всё работает (кроме варианта закрытия программы во время выполнения процесса). Сейчас займусь вниканием в код (теорию)

Rius, "Выжпрограммист" - чётко!!! Вы правы, я не программист по образованию, занимаюсь смежной темой, но очень часто приходится сталкиваться и с этим. Практически нет возможности полностью изучить VB, т.к. буквально во всей литературе, по которой я обучался VB, вообще отсутствуют темы о Процессах, только в одной вскользь освещена Многозадачность на уровне "чайника". Мне же более знакомы языки (Ассемблер) под очень старое железо, которое теперь можно увидеть лишь в музеях ЭВМ 70-80-х годов.

Добавлено через 2 часа 28 минут
vova2112, извиняюсь, это я на радостях поспешил поставить точку, не проверив ваш код . Вы несколько ввели меня в заблуждение словами "Можно сделать так как сказал Rius". Хотя на самом деле лишь вставили переменную, о которой говорил не Rius, а foxkid. Такой вариант я уже давно проходил, он не подходит по причине не остановленного процесса после закрытия программы (выше уже писал). Вот если бы можно было в примере увидеть работу с использованием CancellationToken, о котором говорил Rius, но так и не привёл хоть сколько-то актуального кода... Хотя может если будет время попробую разобраться с его приведённым кодом. Но мои Визуал Студио ругаются на одну строку "InitializeComponent()", говорят, что бы заменил...
0
Эксперт .NET
10575 / 6499 / 1506
Регистрация: 25.05.2015
Сообщений: 19,692
Записей в блоге: 14
08.03.2016, 17:08 11
dymitri, и я и foxkid, посмотрите на время поста. Но это не важно, это метод известный, дубовый и работающий повсюду.
CancellationToken это из .Net 4.0. Которым есть смысл пользоваться, если Вы не привязаны к младшим версиям .Net.
Код я привёл рабочий и актуальный. Только преобразованный из C#. InitializeComponent можно вычеркнуть, в VB она через какие-то костыли вызывается иначе, не из конструктора.

Добавлено через 18 минут
Цитата Сообщение от dymitri Посмотреть сообщение
он не подходит по причине не остановленного процесса после закрытия программы
Он подходит, если поставить булевый флаг при закрытии формы и дождаться завершения потока.
1
0 / 0 / 0
Регистрация: 16.01.2016
Сообщений: 49
08.03.2016, 17:32  [ТС] 12
Rius, Ну да вы оба говорили о флаге, я ещё до этого сам пробовал с переменными для закрытия делать. Но значит просто проблема с закрытием формы. Просто именно вы как-то конкретно стали говорить о CancellationToken, поэтому я и стал надеяться на этот вариант, видя в нём выход.
Цитата Сообщение от Rius Посмотреть сообщение
поставить булевый флаг при закрытии формы и дождаться завершения потока.
Вот именно при закрытии формы как это воплотить? Т.е. как завершить поток там, где его не создавали (процедура)? Может этот момент поможете оформить? (в конце моего примера (первый пост вверху) закомментировано управление закрытием формы). Да, и желательно привязываться к Net 2, т.к. по умолчанию в XP "четвёрки" нет, а хотелось бы совместимости...
0
Эксперт .NET
10575 / 6499 / 1506
Регистрация: 25.05.2015
Сообщений: 19,692
Записей в блоге: 14
08.03.2016, 17:34 13
Раскомментировать метод. Прописать в нём установку переменной и вызвать метод Join() потока.
Чтобы иметь возможность обратиться к потоку, надо сохранить ссылку на него в приватных полях класса формы, а не забыть сразу после запуска. Т.е. переменная потока должна быть не локальной для метода.
0
0 / 0 / 0
Регистрация: 16.01.2016
Сообщений: 49
08.03.2016, 17:47  [ТС] 14
Rius, Дело в том, что потоки в приложении могут создаваться неоднократно, поэтому почитав уйму форумов, нашёл ответ - создание процесса в конкретной локальной процедуре, тогда исчезают множество проблем (создание новых процессов с новыми бесконечными именами, отказ создания с тем же именем, даже если предыдущий процесс уже завершён и т.д.). Поэтому у меня в коде поток создаётся в локальной процедуре, соответственно управление этим процессом невозможно из других процедур. Вот просьба, поясните эти слова:
Цитата Сообщение от Rius Посмотреть сообщение
переменная потока должна быть не локальной для метода
, т.е. наоборот, - не "глобальной", а "приватной"?
0
Эксперт .NET
10575 / 6499 / 1506
Регистрация: 25.05.2015
Сообщений: 19,692
Записей в блоге: 14
08.03.2016, 17:55 15
Цитата Сообщение от dymitri Посмотреть сообщение
, т.е. наоборот, - не "глобальной", а "приватной"?
Не знаю, что такое глобальная в VB.Net, но Вы именно этот способ уже исключили тут:
Цитата Сообщение от dymitri Посмотреть сообщение
Поэтому у меня в коде поток создаётся в локальной процедуре, соответственно управление этим процессом невозможно из других процедур.
В этом случае можно применить свой task factory, коллекционирующий ссылки на запускаемые задачи и с методом ожидания завершения всех ещё незавершённых.
1
0 / 0 / 0
Регистрация: 16.01.2016
Сообщений: 49
08.03.2016, 20:07  [ТС] 16
Опять покажусь чайником , но у меня в коде выше нет никакого "task factory", поэтому
Цитата Сообщение от Rius Посмотреть сообщение
можно применить свой task factory
для меня неактуально, т.к. я понятия не имею что это такое, нигде ни в одной образовательной литературе такого, к сожалению, не встречал... Смотрел сейчас на форумах, лишь по C# пишут... Буду искать, конечно, дальше. Может когда найду, что это такое и где его применить в моём коде... Но всё-равно спасибо, что уделили мне время. Нельзя сказать что у меня пока нет вопросов, просто их так много, и становится всё больше, что лучше пока промолчу, изучу, а там "будем посмотреть".
0
Эксперт .NET
10575 / 6499 / 1506
Регистрация: 25.05.2015
Сообщений: 19,692
Записей в блоге: 14
08.03.2016, 20:17 17
Цитата Сообщение от dymitri Посмотреть сообщение
но у меня в коде выше нет никакого "task factory"
Конечно нету, его надо написать. Класс для создания task/thread, который сохраняет ссылки на них, даже если наружу эти ссылки показывать не надо.
Можно и без этого, просто сохранять запущенные задачи в потокобезопасный список, например. И реализовать их самоудаление оттуда при завершении.
Потому что потом удобно просигналить в один токен о необходимости завершения всех задач, и дождаться их завершения через Task.WaitAll().

Добавлено через 3 минуты

Не по теме:

Цитата Сообщение от dymitri Посмотреть сообщение
Смотрел сейчас на форумах, лишь по C# пишут...
Так это, почему на C# не перейти? Всё равно терять нечего. :pardon:

1
144 / 132 / 34
Регистрация: 28.02.2014
Сообщений: 159
08.03.2016, 20:36 18
Так может стоит использовать BackgroundWorker, т.к. там есть реальный способ остановить процесс выполнения операции?
0
Rius
08.03.2016, 20:40
  #19

Не по теме:

vova2112, у него есть другие неудобства. С момента его появления фреймворк слегка пополнился новыми классами.

0
0 / 0 / 0
Регистрация: 16.01.2016
Сообщений: 49
11.03.2016, 14:11  [ТС] 20
vova2112, Ваш припер кода вверху завершает процедуру, но не завершает процесс при закрытии формы.

Rius, а ваш пример кода завершает все процессы при закрытии, но при попытке осмыслить код, не пойму где указывать (и добавлять в список) запускаемые потоки. Потому что многое в этом коде вижу в первый раз, для меня это "матюки" какие-то .

Т.е. по моему приведённому (и сильно упрощённому) коду актуальных ответов практически не было. Повторюсь десятый раз - литературы обучающей по классам , озвученным Rius, не нашёл, и вообще мало-мальски поясняющей работу потоков, создание списка и т.д. Поэтому вопрос, конечно, остаётся открытым.
Цитата Сообщение от Rius Посмотреть сообщение
Так это, почему на C# не перейти?
Дело в том, что изучение современных языков программирования я как раз и начинал с C++ (после HTML), но ввиду моего начального знания английского, всё же решил не тратить время и изучить Visual Basic, поскольку его старшого брата - Basic 80-х знал в совершенстве, надеялся на некую "совместимость". Хотя признаюсь, на деле кроме совпадения в операторах и некоторых "командах" мало что осталось родственным.
0
11.03.2016, 14:11
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.03.2016, 14:11
Помогаю со студенческими работами здесь

Как правильно завершить поток сервера?
{ Listener = new TcpListener(Settings.ip, Settings.port); // Создаем "слушателя" для...

Как правильно завершить поток QThread и выйти из него?
Здравствуйте, форумчане! Есть GUI-приложение, кнопка в окне приложения запускает цикл обмена...

Как правильно завершить поток (программа часы в Label)
Здравствуйте, есть простая многопоточная программа - на форме в Label отображается время (программа...

Как правильно завершить поток без исключения ThreadInterruptedException?
В общем, есть отдельный проект dll-ки с компонентом, наследующим MonthCalendar. В нем дополнительно...


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

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