Поток, выполняющий удаленное соединение, не прерывается

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

Сначала я запускаю новый поток, отвечающий за получение информации, к которому затем присоединяется основной поток на определенный промежуток времени. Затем я прерываю поток, чтобы отключиться, и, наконец, присоединяюсь к нему, чтобы оставить достаточно времени для выполнения блоков catch и finally.

Теоретически это должно работать отлично: если промежуток времени достаточно короткий, это действительно указывает на то, что сервер не работает (поскольку за короткий выделенный промежуток времени невозможно установить соединение). Но в некоторых случаях, когда сервер действительно не работает, программа просто продолжит выполнение, как если бы исключение ThreadAbortException не имело никакого эффекта. Проблема в том, что эти простои довольно спорадичны, поэтому я не мог сам отлаживать, чтобы увидеть, что не работает должным образом.

Вот как это происходит:

Это основной поток, вызывающий рабочий поток. Очень просто.

public void LaunchCommand()
{
    Thread pingThread = new Thread(new ThreadStart(Ping));
    pingThread.Start();
    while (!pingThread.IsAlive);
    pingThread.Join(new TimeSpan(0, 0, _maxTime)); 
    pingThread.Abort(); //  Time's up.
    pingThread.Join();  //  Make sure we complete everything before moving on
}

И вот вызываемый поток:

private void Ping()
{
    try
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        serviceType = Type.GetTypeFromProgID(serviceProgID, _server, true);
        service = Activator.CreateInstance(serviceType);
        _xmlResult = ApxServiceType.InvokeMember("ExecuteXML", BindingFlags.InvokeMethod, null, service, new string[] { _dataset, Command, string.Empty }) as string;

        stopwatch.Stop();
        _latency = stopwatch.Elapsed;

        // Trivial validations to make sure _status is true, such as _xmlResult.Contains(certainSubString); and such

        _status = true;     //  Everything seems to work fine if we could make up to here.
    }
    catch (ThreadAbortException)
    {
        Console.WriteLine("Server timeout :(");
        return;
    }
    catch (Exception e)
    {
        Console.WriteLine("Server exception: " + e.Message);
        return;
    }
    finally
    {
        if (!_status)
        {
            _latency = new TimeSpan(0, 0, _maxTime);
        }
    }
}

Такие переменные, как Commands, serviceProgID и т. д., были объявлены в другом месте и, как известно, хорошо работают. Я предполагаю, что моя проблема охватывает три строки, следующие за объявлением/инициализацией секундомера. Во-первых, я должен сказать, что скопировал эти строки из аналогичного приложения, но в основном оно должно получать результат только от данной команды. К сожалению, поскольку я не мог отладить в критической ситуации, я не знаю, какая строка проблематична, но в любом случае кажется, что ThreadAbortException не действует. Это потому, что код был отключен на неуправляемый?

Я потерялся здесь, поэтому любая идея будет приветствоваться! Спасибо!


person Literal    schedule 11.10.2012    source источник
comment
Thread.Abort лучше избегать. Во многих ситуациях вызов может вызвать проблемы... см. документацию: msdn. microsoft.com/en-us/library/ty8d3wta.aspx Если возможно, сообщите своему потоку, что пора остановиться, и дайте ему завершиться корректно.   -  person spender    schedule 11.10.2012
comment
Ну, если бы я мог. Но если исключение не сработает, какой сигнал поможет?   -  person Literal    schedule 11.10.2012


Ответы (1)


На самом деле я не вижу необходимости использовать отдельный поток для вашего сценария. Вы можете проверить доступность сервера, используя синхронную операцию. Предлагает ли функция, используемая для проверки доступности сервера, опцию тайм-аута? Если да, то опции тайм-аута должно быть достаточно. Если функция возвращается до истечения времени ожидания, это означает, что сервер находится в сети, иначе сервер не работает.

Если функция проверки доступности сервера не предлагает опцию тайм-аута и может привести к тому, что поток будет ждать вечно (или в течение длительного времени), вы можете использовать новый поток. Однако, если метод Thread.Join(Timeout) возвращает значение true и переменная _status также имеет значение true, вы можете быть уверены, что сервер подключен к сети. Если Thread.Join(Timeout) возвращает false, это будет означать, что сервер не работает.

Рекомендуется использовать Thread.ResetAbort в блоке catch, обрабатывающем исключение Abort. В противном случае среда выполнения повторно вызовет исключение ThreadAbort после завершения выполнения блока catch.

person jags    schedule 11.10.2012
comment
Привет, и спасибо за ваш ответ. Я думаю, вы правы: однако я еще не уверен, что это решит мою проблему, поскольку мошеннический поток будет продолжать работать. Но я думаю, что нет ничего, с чем бы System.Environment.Exit не справился. В любом случае, еще раз спасибо, я обязательно поставлю вам хорошую галочку, если это поможет мне решить проблему. - person Literal; 11.10.2012