开发者

How to resolve poor pattern shutdown thread chasing (re)start thread

Curious pattern of fault tollerent threads and shutting them down in a timely manner. Noticing this pattern recurring through a product a fair bit.

Say you have a fault tolerant process - a network connection - throw in SSL aswell, or a WMI connection and query, or a database connection and query etc.

Your network client connection when it fails will wait a moment (lets say 5 minutes) and then try and re connect.

Now sometimes while this is happening you may also want to stop the networking, this brings in a second thread signaling that it is stopping and performing some shutdown.

If the the fault tolerant process is waiting then it's easy enough to kill off by having it wait on an event managed by the other thread.

How would you stop the Connect function midway through because it has long/costly processes? How to manage steps in Connect() after/during a Cancel() call, it's possible at the moment to call Cancel/Cleanup while Connect is in the process of creating the new SslStream and thus successfuly finish Connect with an incomplete state - m_network set to the new object.

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

private void Connect()
{
    try
    {
        m_netw开发者_如何学Goork.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(); });
}

Making Connect lock or using a local network variable defeats the purpose of trying to kill it off early.

It seems ugly to keep checking the event after each action in the Connect and then calling Cleanup.


Nice thing about async block in F# or async CTP for C# is -- you can externalize handling of cancellation and timeout flows. You can do similar things with TPL and continuations, if you must.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜