Как решить проблему с плохой схемой отключения потока, преследуя (повторно) начальную тему - PullRequest
0 голосов
/ 27 апреля 2011

Любопытная картина неисправности толерантных потоков и своевременного их отключения. Заметив эту закономерность, периодически повторяющуюся через продукт.

Скажем, у вас отказоустойчивый процесс - сетевое соединение - добавьте также SSL, или соединение и запрос WMI, или соединение с базой данных и запрос и т. Д.

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

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

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

Как бы вы остановили функцию Connect на полпути, потому что она имеет длинные / дорогостоящие процессы? Как управлять шагами в Connect() после / во время вызова Cancel(), в данный момент возможно вызвать Отмена / Очистить, когда Connect находится в процессе создания нового SslStream и, таким образом, успешно завершить соединение с неполным состоянием - набор m_network на новый объект.

private TcpClient m_network = new TcpClient();
private ManualResetEvent m_closing = new ManualResetEvent(true);

private void Connect()
{
    try
    {
        m_network.Connect(m_config.Address.Host, m_config.Address.Port);

        SslStream sslStream = new SslStream(m_network.GetStream(), true, ValidateServerCertificate, ClientCertificateSelection );

        X509CertificateCollection clientCertificates = GetClientCertificates();
        sslStream.AuthenticateAsClient(m_config.Address.Host, clientCertificates, SslProtocols.Default, false );

        // do more stuff in a new thread
    }
    catch (System.Exception ex)
    { Reset(); }
}

public void BeginExecution()
{
    ThreadPool.QueueUserWorkItem(delegate
    {
        m_closing.Reset();
        Connect();
    });
}

public void Cancel()
{
    m_closing.Set();
    Cleanup();
}

private void Cleanup()
{
    TcpClient tempClient = m_network;
    m_network = new TcpClient();
    if (tempClient.Connected)
    {
        tempClient.Close();
    }
}

void Reset(){
    if (m_closing.WaitOne(0))
        return;

    Cleanup();

    if (m_closing.WaitOne(TimeSpan.FromSeconds(300)))
        return;

    ThreadPool.QueueUserWorkItem(delegate { Connect(); });
}

Установление блокировки Connect или использование локальной сетевой переменной отрицательно сказывается на попытке убить его раньше.

Кажется уродливым продолжать проверять событие после каждого действия в Connect и затем вызывать очистку.

1 Ответ

1 голос
/ 27 апреля 2011

Хорошая особенность асинхронного блока в F # или асинхронного CTP для C # заключается в том, что вы можете настроить обработку потоков отмены и тайм-аута. Вы можете делать подобные вещи с TPL и продолжениями, если необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...