Прерывание потока по таймауту из кода C#

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43
Перерыл форум, много кто спрашивал о таком коде или кубике, но решения так и нет.

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

Допустим ОСНОВНОЙ метод MainWork выполняется 5 секунд.
А параллельный 10.
После отработки основного потока, программа завершается, но потом выводятся логи параллельного потока.

Но если указать MainWork 10 секунд, а таймаут 5, и после таймаута выбросить исключение, то вырубается полностью и PM и ZP.

Кто-то может подскажет, как это можно реализовать?
Чтобы в случае успеха основного потока (MainWork) завершался параллельный поток.
А в случае если у параллельного потока закончилось время выполнения, то прерывался шаблон и основной и параллельный поток, БЕЗ падения ZP и PM?

OwnCode:
namespace ZennoLab.OwnCode
{
    /// <summary>
    /// A simple class of the common code
    /// </summary>
    public class CommonCode
    {
        IZennoPosterProjectModel project;

        public CommonCode(IZennoPosterProjectModel project)
        {
            this.project = project;
        }
        
        /// <summary>
        /// Lock this object to mark part of code for single thread execution
        /// </summary>
        public static object SyncObject = new object();
        
        
        public void Start()
        {
            project.SendInfoToLog("Start() Start");

            TimeOutAsync(10);
            
            MainWork(5);
            project.SendInfoToLog("Start() Finish");

        }

        /// <summary>
        /// Основная работа
        /// </summary>
        /// <param name="seconds"></param>
        private void MainWork(int seconds)
        {
            project.SendInfoToLog("Основной поток MainWork() Start");
            
            while (seconds >= 0)
            {
                project.SendInfoToLog(seconds.ToString());
                Thread.Sleep(1000);
                seconds--;
            }
            
            project.SendInfoToLog("Основной поток MainWork() Finish");
        }

        /// <summary>
        /// Асинхронный метод для вызова "Отсчёта максимального времени выполнения приложения"
        /// </summary>
        /// <param name="seconds"></param>
        private async void TimeOutAsync(int seconds)
        {
            project.SendInfoToLog("TimeOutAsync() Start");
            await Task.Run(() => TimeOut(seconds));
            project.SendInfoToLog("TimeOutAsync() Finish");
        }

        /// <summary>
        /// Отсчёт максимального времени выполнения приложения
        /// </summary>
        /// <param name="seconds"></param>
        private void TimeOut(int seconds)
        {
            project.SendInfoToLog("TimeOut() Start");
            var ts = new TimeSpan(0, 0, seconds);
            var sw = Stopwatch.StartNew();
            while (sw.Elapsed < ts)
            {
                Thread.Sleep(1000);
            }
            
            project.SendInfoToLog("TimeOut() Finish");
            //throw new Exception("TimeOut() Exception");
        }

    }
}
Вызываю вот так
C#:
var common = new CommonCode(project);
common.Start();

Давайте вместе сделаем что-то такое, из-за чего не будут висеть инстансы.
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 690
Баллы
113

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43
очень интересно, но непонятно :-)
Цель то конечная какая ? лично я вот не уловил....
Цель вот какая.

Допустим есть шаблон (SuperPuper.zp) он выполняется от 5 до 10 минут.
Но в последнее время он начал зависать (писал в ветку 7.2.0.0).
Ни "Остановить" ни "Прервать" не получается. Лечится только полным перезапуском зеннопостера.

Так вот создав параллельный поток, можно будет установить таймаут выполнения допустим 15 минут (больше чем нужно самому шаблону).

И если этот поток работает 15 минут, то значит он завис, и его нужно прервать, чтобы освободить поток (зеннопостер) для следующего выполнения.
 
  • Спасибо
Реакции: 606

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 690
Баллы
113
ааа.... вон чо...
ну идея конечно интересная. но с кучей нюансов по стабильности. может для начала все таки трассировку сделать и выявить места где шаб начинает зависать ?
сузить круг подозреваемых так сказать :-)
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 690
Баллы
113

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 690
Баллы
113
еще в кубиках C# можно использовать такую конструкцию внутри цикла.
C#:
for (int i = 0; i<60; i++ ) {                                                                                                 
    ///// -------------------------------выход по внешнему требованию---------------------------------------------------------------------------------//
    if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) throw new Exception("");
    if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode)  throw new Exception("");
    ///-----------------------------------------------------------------------------------------------------------------------------------------------//
    Thread.Sleep(3000);         // пауза между итерациями
}
например цикл ожидания чего либо, и вот эти два условия проверяют как раз нет ли прерывания шаблона. проверил только что на 7.2.0.0 нормально прерывают.
ну и до кучи, вдруг не читали https://zennolab.com/discussion/threads/lovim-zavisshie-instansy.72949/ :df:
 
  • Спасибо
Реакции: 606 и ZSharp

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43
еще в кубиках C# можно использовать такую конструкцию внутри цикла.
C#:
for (int i = 0; i<60; i++ ) {                                                                                               
    ///// -------------------------------выход по внешнему требованию---------------------------------------------------------------------------------//
    if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) throw new Exception("");
    if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode)  throw new Exception("");
    ///-----------------------------------------------------------------------------------------------------------------------------------------------//
    Thread.Sleep(3000);         // пауза между итерациями
}
например цикл ожидания чего либо, и вот эти два условия проверяют как раз нет ли прерывания шаблона. проверил только что на 7.2.0.0 нормально прерывают.
Попробовал в свой код это вставить, всё равно PM вырубается.

Почитал, но у меня весь код в Общем Коде. Тоже не подходит ((
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 761
Благодарностей
2 401
Баллы
113
Если запущено 2 задачи - и нужно завершить вторую, когда завершится первая - то можно использовать токены отмены.
А чтобы понять, какой поток завершился сам по себе успешно, а какой например по токену отмены - то возможно есть смысл создать две переменные, в которых делать пометки, как именно завершил работу нужный поток.
И тогда, когда уже мы завершили работу методов согласно условиям с помощью токена отмены - в методе Start проверяем, как завершился нужный поток - и если он завершился по токену отмены - бросаем исключение.

Я попробовал чуток подкорректировать Ваш код, согласно данным требованиям.
Но, длительное время не тестировал - могут вылезать разные косяки (следовал задачи показать как это можно реализовать, но не знаю насколько это правильно).
 

Вложения

  • Спасибо
Реакции: Meteorburn и ZSharp

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43
Если запущено 2 задачи - и нужно завершить вторую, когда завершится первая - то можно использовать токены отмены.
А чтобы понять, какой поток завершился сам по себе успешно, а какой например по токену отмены - то возможно есть смысл создать две переменные, в которых делать пометки, как именно завершил работу нужный поток.
И тогда, когда уже мы завершили работу методов согласно условиям с помощью токена отмены - в методе Start проверяем, как завершился нужный поток - и если он завершился по токену отмены - бросаем исключение.

Я попробовал чуток подкорректировать Ваш код, согласно данным требованиям.
Но, длительное время не тестировал - могут вылезать разные косяки (следовал задачи показать как это можно реализовать, но не знаю насколько это правильно).
o_O Нужно разбираться, но вроде оно. Спасибо.


а вот эта настройка тоже не помогает ?

Посмотреть вложение 64923
Простояло ночь, было 4 прерывания (Поток прерван по таймауту).
Вроде всё работает, но нагрузка почему-то высокая.
Сложилось впечатление, что поток просто освобождается для зеннопостера, а сам инстанс остаётся висеть.
 

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43
Если запущено 2 задачи - и нужно завершить вторую, когда завершится первая - то можно использовать токены отмены.
А чтобы понять, какой поток завершился сам по себе успешно, а какой например по токену отмены - то возможно есть смысл создать две переменные, в которых делать пометки, как именно завершил работу нужный поток.
И тогда, когда уже мы завершили работу методов согласно условиям с помощью токена отмены - в методе Start проверяем, как завершился нужный поток - и если он завершился по токену отмены - бросаем исключение.

Я попробовал чуток подкорректировать Ваш код, согласно данным требованиям.
Но, длительное время не тестировал - могут вылезать разные косяки (следовал задачи показать как это можно реализовать, но не знаю насколько это правильно).
Наверное не подходит.
Токены нужно передавать в каждый метод, а их у меня очень много в проектах.
Конечно сразу подумал создать поле или свойство в классе и проверять когда нужно. Но почитал комменты на метаните, и там отлично объясняют, что так делать нельзя.
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 761
Благодарностей
2 401
Баллы
113

volody00

Client
Регистрация
06.09.2016
Сообщения
793
Благодарностей
812
Баллы
93

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43
Может если нельзя вызвать исключение, то можно сразу убивать процесс (если, конечно, сможешь вычислить нужный) - https://zennolab.com/discussion/threads/kak-uznat-pid-processa-po-imeni-v-zenno.83844/#post-563408
На сколько я помню, то в одном процессе несколько потоков. То есть убив процесс, лягут ещё другие потоки.
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 690
Баллы
113
На сколько я помню, то в одном процессе несколько потоков. То есть убив процесс, лягут ещё другие потоки.
ну если работать под лисой 45-й, то лягут. а вот в других движках всегда один процес на один поток.
 

ZSharp

Client
Регистрация
29.09.2013
Сообщения
387
Благодарностей
121
Баллы
43

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