Остановка потоков из общего кода.

artomka

Client
Регистрация
23.08.2018
Сообщения
159
Реакции
94
Баллы
28
Никак немогу разобраться с правильным завершением текущего потока из общего кода.

Пробовал через асинк метод выбрасывать ошибки/Environment.Exit() и в итоге закрывается сама зенка а не текущий поток.

Также пробовал через System.Threading.Thread.CurrentThread.Abort(); но это лишь закрывает текущий асинк метод.

Возможно кто сталкивался и может подсказать что не так?
 
П.С. при вызове System.Threading.Thread.CurrentThread.Abort(); из самой зенки летят забаные ошибки но поток не убивается.
pNZT3l5.png
 
почему бы не выходить так как это предусмотрено для всех, через goodend или badend ?
отлов зависших потоков.

а если так:
C#:
Развернуть Свернуть Копировать
ZennoPoster.StopTask(Guid.Parse(project.TaskId));
так останвливается выполнение всех потоков зп.
 
что бы поток закрылся принудительно через определенный промежуток времени и вышел на BanEnd, надо поставить галочку и уставку времени.
70612


и оптимизировать шаблон так, что бы он хоть иногда выходил на межкубовые линии, так как эта настройка работает только в тех местах.
в циклах c# надо вставлять такие конструкции
C#:
Развернуть Свернуть Копировать
// выход по внешнему требованию
if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) throw new Exception("Внешнее прерывание");
if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode)  throw new Exception("Внешнее прерывание");

подробнее описывал тут https://zennolab.com/discussion/threads/lovim-zavisshie-instansy.72949/

а все эти махинации с жестким убиванием потока, это до добра не приведут, так как идентифицировать отдельный поток в зенке, ну очень проблематично.
 
  • Спасибо
Реакции: artomka
что бы поток закрылся принудительно через определенный промежуток времени и вышел на BanEnd, надо поставить галочку и уставку времени.
Посмотреть вложение 70612

и оптимизировать шаблон так, что бы он хоть иногда выходил на межкубовые линии, так как эта настройка работает только в тех местах.
в циклах c# надо вставлять такие конструкции
C#:
Развернуть Свернуть Копировать
// выход по внешнему требованию
if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) throw new Exception("Внешнее прерывание");
if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode)  throw new Exception("Внешнее прерывание");

подробнее описывал тут https://zennolab.com/discussion/threads/lovim-zavisshie-instansy.72949/

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

Cпасибо за статью но воспользовался решением от Verbin.

thread.Interrupt() и все работает как нужно ( но только в зп).

П.С. по поводу таймаута зенновского то он работает 50/50 с чем это связанно я не знаю.

Ну а по поводу оптимизации проекта + проверкам в кубиках c#, то это все конечно хорошо но тут нужно было решение без переписывания 100 кубиков :D поэтому просто асинк таймер + жесткий стоп через метод указанный выше работают на ура.
 
  • Спасибо
Реакции: VerBin
Тестовый c# кубик в проекте:
Развернуть Свернуть Копировать
// запускаем проверку в дочернем потоке с таймаутом в 5 секунд
project.Exit(5);

// имитируем долгое выполнение в течении 10 секунд
for (int counter = 0; counter < 10; counter++)
{
    project.SendInfoToLog($"Поток: {Thread.CurrentThread.ManagedThreadId} Счетчик: {counter}", true);
    Thread.Sleep(1000);
}

Класс в общем коде:
Развернуть Свернуть Копировать
public static class ProjectExtensions
{
    /// <summary>
    /// Остановить выполнение проекта по таймауту
    /// </summary>
    public static void Exit(this IZennoPosterProjectModel project, int timeoutInSeconds)
    {
        Thread thread = Thread.CurrentThread;
        System.Threading.Tasks.Task.Run(() =>
                                        {
                                            int counter = 0;

                                            while (true)
                                            {
                                                Thread.Sleep(1000);
                                                counter++;

                                                if (counter > timeoutInSeconds)
                                                {
                                                    project.SendInfoToLog($"Останавливаем поток по таймауту: {thread.ManagedThreadId}", true);
                                                    thread.Interrupt();

                                                    break;
                                                }
                                            }
                                        });
    }
}
 

Вложения

  • exit.zp
    exit.zp
    12,9 KB · Просмотры: 233
// запускаем проверку в дочернем потоке с таймаутом в 5 секунд
project.Exit(5);
Нет, ну круто, конечно, чё... И как раз ответ на вопрос, который меня долго мучил... Но только если основной поток завершаентся раньше фонового, вся зенка крэшится!
Вопрос в том, почему и как этого избежать? Крэшится на строке thread.Interrupt(); в общем коде.
 

Вложения

  • exit.zp
    exit.zp
    12,5 KB · Просмотры: 210
Последнее редактирование:
ну что , доработаем этот костыль ? :)

а что если внутрь параллельного вставить этот код ?
C#:
Развернуть Свернуть Копировать
// выход по внешнему требованию
if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) {thread.Interrupt(); break;}
if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode)  {thread.Interrupt(); break;}

пробовать не буду, сами пробуйте :)
 
Нет, ну круто, конечно, чё... И как раз ответ на вопрос, который меня долго мучил... Но только если основной поток завершаентся раньше фонового, вся зенка крэшится!
Вопрос в том, почему и как этого избежать? Крэшится на строке thread.Interrupt(); в общем коде.
Ответил вам в личку но напишу еще раз тут.

Зенка не крашится а кладет поток, в ПМ он всего 1 и соотвестенно кладется весь ПМ. В зп таких проблем не будет.

ну что , доработаем этот костыль ? :-)

а что если внутрь параллельного вставить этот код ?
C#:
Развернуть Свернуть Копировать
// выход по внешнему требованию
if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) {thread.Interrupt(); break;}
if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode)  {thread.Interrupt(); break;}

пробовать не буду, сами пробуйте :-)

Чуть позже опробую когда закончу дела.
 
Нет, ну круто, конечно, чё... И как раз ответ на вопрос, который меня долго мучил... Но только если основной поток завершаентся раньше фонового, вся зенка крэшится!
Вопрос в том, почему и как этого избежать? Крэшится на строке thread.Interrupt(); в общем коде.
Да действительно, если фоновый поток работает дольше основного, то зенка вылетает.
Сейчас выложу обновленное решение..
 
Переработал и протестировал код.
Обновленное решение работает стабильно в ProjectMaker и ZennoPoster.

В общий код добавляем класс:
C#:
Развернуть Свернуть Копировать
public class Timeout
{
    private IZennoPosterProjectModel _project = null;
    private int _timeoutInSeconds = 0;
    private CancellationTokenSource _cancellationTokenSource = null;

    public Timeout(IZennoPosterProjectModel project, int timeoutInSeconds)
    {
        _project = project;
        _timeoutInSeconds = timeoutInSeconds;
        _cancellationTokenSource = new CancellationTokenSource();

    }

    public void Start()
    {
        var thread = Thread.CurrentThread;
        System.Threading.Tasks.Task.Factory.StartNew(() =>
                                                     {
                                                         _project.SendInfoToLog($"Запускаем фоновый поток: {Thread.CurrentThread.ManagedThreadId}", true);
                                                         var endTime = DateTime.Now.AddSeconds(Convert.ToDouble(_timeoutInSeconds));
                                                         while (true)
                                                         {
                                                             Thread.Sleep(100);

                                                             if (_cancellationTokenSource.Token.IsCancellationRequested)
                                                             {
                                                                 _project.SendInfoToLog($"Останавливаем фоновый поток: {Thread.CurrentThread.ManagedThreadId}", true);
                                                                 break;
                                                             }

                                                             var currentTime = DateTime.Now;
                                                             if (currentTime >= endTime)
                                                             {
                                                                 _project.SendInfoToLog($"Останавливаем основной поток: {thread.ManagedThreadId}", true);
                                                                 _project.SendInfoToLog($"Останавливаем фоновый поток: {Thread.CurrentThread.ManagedThreadId}", true);
                                                                 thread.Interrupt();
                                                                 break;
                                                             }
                                                         }
                                                     }, _cancellationTokenSource.Token);
    }

    public void Stop()
    {
        _cancellationTokenSource.Cancel();
        Thread.Sleep(1000);
    }
}

Первый кубик в проекте для запуска фонового потока с проверкой по таймауту:
C#:
Развернуть Свернуть Копировать
// запускаем проверку в фоновном потоке с таймаутом в 5 секунд
project.Context["timeout"] = new Timeout(project, 5);
(project.Context["timeout"] as Timeout).Start();

Второй кубик в проекте для имитации выполнения разных задач:
C#:
Развернуть Свернуть Копировать
// имитируем долгое выполнение в течении 10 секунд
for (int counter = 0; counter < 10; counter++)
{
    project.SendInfoToLog($"Поток: {Thread.CurrentThread.ManagedThreadId} Счетчик: {counter}", true);
    Thread.Sleep(1000);
}

Кубик завершения проекта по Bad End и Good End для завершения фонового потока:
C#:
Развернуть Свернуть Копировать
(project.Context["timeout"] as Timeout).Stop();

Прикрепил к сообщению тестовый проект, работает на версии 7.2 и выше.

Если вам пригодилось решение, достаточно нажать на кнопку Спасибо под сообщением.
 

Вложения

  • exit.zp
    exit.zp
    16,7 KB · Просмотры: 249
Последнее редактирование:
ну все :)
прям рабочий механизм для запуска многопоточных процедур в зенке. щас все начнут запускать распараллеливание :)
 
ну все :-)
прям рабочий механизм для запуска многопоточных процедур в зенке. щас все начнут запускать распараллеливание :-)
Я бы назвал это костылем.
Но все-же, кому-то это решение крайне необходимо.
 
Последнее редактирование:
позанудствую :)
после _cancellationTokenSource.Cancel(); я бы все же поставил небольшую паузу. хоть в параллельном потоке и стоит достаточно маленькая пауза в 100 мс. но разрыв все равно есть.
 
  • Спасибо
Реакции: VerBin
позанудствую :-)
после _cancellationTokenSource.Cancel(); я бы все же поставил небольшую паузу. хоть в параллельном потоке и стоит достаточно маленькая пауза в 100 мс. но разрыв все равно есть.
Логично. Обновил код в сообщении.
 
Последнее редактирование:
я это.... не то что придираюсь .... :)
не пойму что вот это за условие такое на скрине, у меня оно всегда в false и выполнение кода идет бесконечно.

70710
 
я это.... не то что придираюсь .... :-)
не пойму что вот это за условие такое на скрине, у меня оно всегда в false и выполнение кода идет бесконечно.

Посмотреть вложение 70710
Это проверка жив ли основной поток. Можешь удалить. Вставил на всякий случай.
Обновил код, перезалил проект.
 
Последнее редактирование:
  • Спасибо
Реакции: artomka
Переработал и протестировал код.
Обновленное решение работает стабильно в ProjectMaker и ZennoPoster.
Спасибо большое! Очень ценная информация. Я пока до совсем многопоточного программирования не вырос, так что придется сделать левел ап чтобы понять полностью. Но код рабочий, все супер! Вы таки мастер! )
 
Чуть попроще сделал с моей точки зрения аматора в многопоточности. Один экшен, один снипет. В общую коллекцию.
C#:
Развернуть Свернуть Копировать
Thread thread = Thread.CurrentThread;
Task.Factory.StartNew(()=>
{
    while (thread.IsAlive)
    {
        project.SendInfoToLog("Фоновый поток", true);
        
        // Какие-то действия, эмулируем ожиданием
        project.SendInfoToLog("Фоновый поток - Первое ожидание. Состояние основного потока: " + thread.IsAlive.ToString(), true);
        Thread.Sleep(1000);
        project.SendInfoToLog("Фоновый поток - Второе ожидание. Состояние основного потока: " + thread.IsAlive.ToString(), true);
        Thread.Sleep(1000);
        
        project.SendInfoToLog("Фоновый поток - прерывание основного потока. Состояние основного потока: " + thread.IsAlive.ToString(), true);
        thread.Interrupt();
    }
    project.SendInfoToLog("Фоновый поток конец", true);
}
);
project.SendInfoToLog("Основной поток", true);

// Какие-то действия, эмулируем ожиданием
Thread.Sleep(10000);

project.SendInfoToLog("Основной поток конец", true);
 

Вложения

Чуть попроще сделал с моей точки зрения аматора в многопоточности. Один экшен, один снипет. В общую коллекцию.
у тебя весь шаблон из одного сниппета состоит ?
 
у тебя весь шаблон из одного сниппета состоит ?
Да, но он не вполне корректно работает, как оказалось. Немного не та цель выполняется.
Если действия описаны и выполняются в пределах этого одного кубика - все норм. Фоновый поток мониторит основной поток (жив ли он), ожидает немного (вместо ожидания можно прописать свои действия) прерывает его и завершается сам. Но как только действие шаблона переходит к выполнению других кубиков, прерывание основного потока не происходит. Вероятно потому, что при выполнении каждого последующего кубика создаётся новы поток. По крайней мере идентификатор потока (его номер) другой.
 
походу ты запутался в шаблонах, потоках и иже там :)
я тебя спрашивал про твой шаблон. ты говоришь что весь шаблон состоит из одного кубика, и тут же говоришь что на следующем кубике код не работает.
конечно он не работает, ты же вызываешь thread.Interrupt(); в том же кубике в котором и вызываешь запуск кода.
вот здесь https://zennolab.com/discussion/threads/ostanovka-potokov-iz-obschego-koda.87667/post-589411
все разложено как и что вызывать, как завершать. а твой вариант не имеет смысла совсем. ну может и имеет для контроля конкретного одного кубика, но ни как не относится к теме топика, а именно контролю всего проекта.
 
Переработал и протестировал код.
Обновленное решение работает стабильно в ProjectMaker и ZennoPoster.

В общий код добавляем класс:
C#:
Развернуть Свернуть Копировать
public class Timeout
{
    private IZennoPosterProjectModel _project = null;
    private int _timeoutInSeconds = 0;
    private CancellationTokenSource _cancellationTokenSource = null;

    public Timeout(IZennoPosterProjectModel project, int timeoutInSeconds)
    {
        _project = project;
        _timeoutInSeconds = timeoutInSeconds;
        _cancellationTokenSource = new CancellationTokenSource();

    }

    public void Start()
    {
        var thread = Thread.CurrentThread;
        System.Threading.Tasks.Task.Factory.StartNew(() =>
                                                     {
                                                         _project.SendInfoToLog($"Запускаем фоновый поток: {Thread.CurrentThread.ManagedThreadId}", true);
                                                         var endTime = DateTime.Now.AddSeconds(Convert.ToDouble(_timeoutInSeconds));
                                                         while (true)
                                                         {
                                                             Thread.Sleep(100);

                                                             if (_cancellationTokenSource.Token.IsCancellationRequested)
                                                             {
                                                                 _project.SendInfoToLog($"Останавливаем фоновый поток: {Thread.CurrentThread.ManagedThreadId}", true);
                                                                 break;
                                                             }

                                                             var currentTime = DateTime.Now;
                                                             if (currentTime >= endTime)
                                                             {
                                                                 _project.SendInfoToLog($"Останавливаем основной поток: {thread.ManagedThreadId}", true);
                                                                 _project.SendInfoToLog($"Останавливаем фоновый поток: {Thread.CurrentThread.ManagedThreadId}", true);
                                                                 thread.Interrupt();
                                                                 break;
                                                             }
                                                         }
                                                     }, _cancellationTokenSource.Token);
    }

    public void Stop()
    {
        _cancellationTokenSource.Cancel();
        Thread.Sleep(1000);
    }
}

Первый кубик в проекте для запуска фонового потока с проверкой по таймауту:
C#:
Развернуть Свернуть Копировать
// запускаем проверку в фоновном потоке с таймаутом в 5 секунд
project.Context["timeout"] = new Timeout(project, 5);
(project.Context["timeout"] as Timeout).Start();

Второй кубик в проекте для имитации выполнения разных задач:
C#:
Развернуть Свернуть Копировать
// имитируем долгое выполнение в течении 10 секунд
for (int counter = 0; counter < 10; counter++)
{
    project.SendInfoToLog($"Поток: {Thread.CurrentThread.ManagedThreadId} Счетчик: {counter}", true);
    Thread.Sleep(1000);
}

Кубик завершения проекта по Bad End и Good End для завершения фонового потока:
C#:
Развернуть Свернуть Копировать
(project.Context["timeout"] as Timeout).Stop();

Прикрепил к сообщению тестовый проект, работает на версии 7.2 и выше.

Если вам пригодилось решение, достаточно нажать на кнопку Спасибо под сообщением.

А можно ли сделать так, чтобы поток не убивался, а просто ребутился инстанс и задача продолжала выполнение?
 

Кто просматривает тему: (Всего: 0, Пользователи: 0, Гости: 0)