Управление потоком наблюдателя — как работает возбужденное исключение и присоединение?

У меня есть процесс входа в систему из API, которым я не владею, который иногда зависает. Если это занимает больше, чем, скажем, 30 секунд, я хотел бы убить его и повторить попытку (поскольку это должно занять всего около 2-3).

Я немного смущен тем, как работают прерывающие потоки, и нужно ли мне присоединяться после прерывания. Вот мои вопросы, за которыми следует пример того, что я пытаюсь сделать:

Вопросы:

  1. Abort вызывает исключение прерывания потока в потоке, в котором он был вызван. Это распространяется? Нужно ли мне явно обрабатывать это в вызывающем потоке или поток просто умирает?

  2. Нужно ли мне присоединяться к прерванному потоку, чтобы он не превратился в зомби, или я просто запутался в мире программирования *NIX?

    public static Session GetSession()
    {
        Session session = new Session("user", "pass");
    
        try
        {
            //Create a thread to get the session so we can kill it if it hangs.
            Thread thread = new Thread(() => session.Logon());
    
            //Create a thread to kill the session thread if it hangs.
            Thread watcher = new Thread(() => HangKill(thread));
    
            //Start both threads.
            thread.Start();
            watcher.Start();
    
            //Wait for session thread to finish - abort kill thread if it does.
            thread.Join();
            watcher.Abort();
            watcher.Join();
        }
        catch (Exception ex)
        {            
            status = ex.ToString();
        }
    
        return session;
    }
    
    
    public static void HangKill(Thread t)
    {
        Thread.Sleep(30);
    
        if (t.IsAlive == true)
        {
            t.Abort();
        }
    }
    

person John Humphreys    schedule 19.07.2012    source источник
comment
Thread.Abort() крайне опасен.   -  person SLaks    schedule 19.07.2012
comment
Извиняюсь за дерьмовое редактирование, но я не могу сделать так, чтобы имена функций были частью блоков кода.   -  person John Humphreys    schedule 19.07.2012
comment
@SLaks - Спасибо, как еще я могу этого добиться, должен быть стандартный способ :)   -  person John Humphreys    schedule 19.07.2012
comment
Нет. Прерывание задачи без ее участия по своей сути небезопасно, поскольку вы не знаете, что вы убиваете.   -  person SLaks    schedule 19.07.2012
comment
Да, это имеет смысл. Спасибо.   -  person John Humphreys    schedule 19.07.2012
comment
сколько раз вы хотите повторить?   -  person Estefany Velez    schedule 19.07.2012
comment
Всего пара :p Я думаю, что у меня есть ответ, метод, который я использовал, очевидно, не был хорошей идеей - я найду другой способ обойти это.   -  person John Humphreys    schedule 19.07.2012
comment
Вам подойдет класс Timeout.   -  person Estefany Velez    schedule 19.07.2012


Ответы (1)


Прерывание потоков в собственном процессе опасно. (Тем не менее, как и в других процессах.) Поток может владеть некоторыми блокировками, может находиться в процессе обновления критических структур и т. д. Так что это не тот путь.

Я бы предложил включить рассматриваемую службу в другой процесс, чтобы вы могли убить этот процесс, если что-то пойдет не так. Используйте IPC (общая память? WCF?) для связи с этим процессом.

person Vlad    schedule 19.07.2012
comment
Спасибо. Это кажется очень тяжелым из-за того, что вы просто хотите прервать вход в систему, который зависает. Разве нет простого способа убить поток из его родительского (создающего) потока? Или мне нужно пойти по маршруту C# версии временного ожидания потока, сигнализации и условных переменных? - person John Humphreys; 19.07.2012
comment
@ w00te: нет, на самом деле это неправильный способ. Простите за это. Поток может безопасно завершиться, перейдя в конец функции потока, но это максимум, что вы можете сделать. И это не поможет, если потоки зависнут в коде, которым вы не владеете. - person Vlad; 19.07.2012
comment
Ха-ха, хорошо. Думаю, я облажался. Могу я спросить, что бы вы сделали в такой же ситуации (не обязательно то, что вы считаете лучшей практикой?) - person John Humphreys; 19.07.2012
comment
@w00te: Ну, если код, который вам нужно запустить, небезопасен * сбой, зависание, что угодно), я бы построил вокруг него стену с замками и вооруженной охраной, то есть запустил бы его в другом процессе. Несколько более легким способом может быть игра с AppDomains (вы можете выгрузить один), но, возможно, это слишком сложно, чтобы тратить на это время. - person Vlad; 19.07.2012
comment
@ w00te: в любом случае, держать сбой / зависание кода, работающего как можно дальше от вашего кода, должно быть хорошей идеей в любой среде, будь то нативная или управляемая. - person Vlad; 19.07.2012
comment
Поднять еще один процесс и IPC для входа в систему? Вы бы сделали это? Действительно? - person Martin James; 19.07.2012
comment
@Martin: Выполнять зависший код с ошибками в моем процессе - я бы не стал этого делать, правда. У вас есть лучший вариант? - person Vlad; 19.07.2012