繁体   English   中英

处理后完成一个线程循环

[英]Finishing up a thread loop after disposal

我正在寻找C#中的线程安全代码,如果可能的话,将避免两个问题;

  1. 如果线程对象在任何点被丢弃,则线程循环很好地退出。
  2. 当由另一个类或表单(特别是表单)使用时,使用该类的开发人员不必记住挂钩表单的close事件并调用dispose。 例如, 正确完成服务器线程

线程正在调用一个具有以下while循环的方法;

while (!Finished)
{
    string request = "";
    try
    {
        //Block until we have a message or we are terminated in dispose **
        request = server.Recv(Encoding.Unicode);  
        //Send a response to the sender so they know we received. 
        server.Send(request, Encoding.Unicode);
    }
    catch (Exception e)
    {
        //Catch a termination error. 
        if (e.Errno == ETERM)
        {
            break;
        }
    }
    syncContext.Post(
                     new SendOrPostCallback(delegate(object state)
                     {
                         MessageHandler handler = OnMessage;
                         if (handler != null)
                         {
                             handler(request);
                         }
                     }), null);
}

处置目前看起来像这样;

public void Dispose()
{
    Finished = true;
    //Cause all blocking message requests and sends to terminate with exception ** 
    FZMQConext.Dispose();

    //Wait for the thread to finish up.
    FThread.Join();
    GC.SuppressFinalize(this);
}

我认为的问题是;

  • 我的事件可以被调用,即使我正在处理我的类,因为线程必须完成推出。 在try / catch和syncContext.Post()之间调用dispos。 这有多糟糕?
  • 有没有办法结束这个类,所以它的用户不必记得调用dispose。 目前,如果他们没有应用程序坐在那里等待线程完成,它永远不会。 将它设置为后台线程似乎很懒惰。

我的事件可以被调用,即使我正在处理我的类,因为线程必须完成推出。 在try / catch和syncContext.Post()之间调用dispos。 这有多糟糕?

它看起来并不那么糟糕。 一旦你设置Finished=true 它应该完成发布一个新的委托,然后退出循环。 但是,您可能会遇到Finished CPU缓存问题。 运行循环的CPU核心可以另一个线程更改了值读取Finished缓存值,因此循环可能会错误地继续运行。 要防止这种情况,您应该创建一个仅通过Interlocked修改的私有字段,以及一个修改该字段的方法:

private int _running = 1;
public void Stop()
{
    Interlocked.Exchange(ref _running, 0);
}

并且循环将while( _running > 0)

有没有办法结束这个类,所以它的用户不必记得调用dispose。 目前,如果他们没有应用程序坐在那里等待线程完成,它永远不会。 将它设置为后台线程似乎很懒惰。

实际上没有一般方法可以避免将处置负担放在客户身上。 但是如果这个类总是被Winforms组件使用,那么你可以编写一个构造函数来获取父组件并订阅父组件的Disposed事件。 因此,当处理父组件(例如表单)时,此对象也会被处置:

public MyClass(Component parent)
{
    parent.Disposed += (s,e) => this.Dispose();
}

(我会把终结器作为一个选项扔出去,因为无法确定是否/什么时候会运行。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM