简体   繁体   English

处理后完成一个线程循环

[英]Finishing up a thread loop after disposal

I am looking for thread safe code in C# that will avoid two issues if possible; 我正在寻找C#中的线程安全代码,如果可能的话,将避免两个问题;

  1. If the thread object is disposed of at any point the thread loop exits nicely. 如果线程对象在任何点被丢弃,则线程循环很好地退出。
  2. When used by another class or form (in-particular a form) the developer using the class doesn't have to remember to hook the close event of the form and call dispose. 当由另一个类或表单(特别是表单)使用时,使用该类的开发人员不必记住挂钩表单的close事件并调用dispose。 Eg Correct finishing of server's thread 例如, 正确完成服务器线程

The thread is calling a method which has the following while loop; 线程正在调用一个具有以下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);
}

And the dispose currently looks like so; 处置目前看起来像这样;

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);
}

Issues as I see it are; 我认为的问题是;

  • My event could be called even though I am disposing of my class as the thread has to finish rolling out. 我的事件可以被调用,即使我正在处理我的类,因为线程必须完成推出。 Say disposed is called between the try/catch and the syncContext.Post(). 在try / catch和syncContext.Post()之间调用dispos。 How bad is this? 这有多糟糕?
  • Is there any way of wrapping up this class so the user of it doesn't have to remember to call dispose. 有没有办法结束这个类,所以它的用户不必记得调用dispose。 Currently if they don't the application sits there waiting for the thread to finish, which it never will. 目前,如果他们没有应用程序坐在那里等待线程完成,它永远不会。 Setting it to a background thread seems lazy. 将它设置为后台线程似乎很懒惰。

My event could be called even though I am disposing of my class as the thread has to finish rolling out. 我的事件可以被调用,即使我正在处理我的类,因为线程必须完成推出。 Say disposed is called between the try/catch and the syncContext.Post(). 在try / catch和syncContext.Post()之间调用dispos。 How bad is this? 这有多糟糕?

It doesn't look that bad. 它看起来并不那么糟糕。 Once you set Finished=true . 一旦你设置Finished=true it should finish posting a new delegate and then exit the loop. 它应该完成发布一个新的委托,然后退出循环。 However, you might run into CPU caching issues with Finished . 但是,您可能会遇到Finished CPU缓存问题。 The CPU core running the loop could read the cached value of Finished after another thread has changed the value, so the loop could erroneously continue running. 运行循环的CPU核心可以另一个线程更改了值读取Finished缓存值,因此循环可能会错误地继续运行。 To prevent this, you should create a private field that is only modified via Interlocked , and a method that modifies that field: 要防止这种情况,您应该创建一个仅通过Interlocked修改的私有字段,以及一个修改该字段的方法:

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

and the loop would run while( _running > 0) . 并且循环将while( _running > 0)

Is there any way of wrapping up this class so the user of it doesn't have to remember to call dispose. 有没有办法结束这个类,所以它的用户不必记得调用dispose。 Currently if they don't the application sits there waiting for the thread to finish, which it never will. 目前,如果他们没有应用程序坐在那里等待线程完成,它永远不会。 Setting it to a background thread seems lazy. 将它设置为后台线程似乎很懒惰。

There's really no general way to avoid putting the burden of disposing on the clients. 实际上没有一般方法可以避免将处置负担放在客户身上。 But if this class is meant to be always used by, say Winforms components, then you could write a constructor that takes a parent component and subscribe to the Disposed event of the parent. 但是如果这个类总是被Winforms组件使用,那么你可以编写一个构造函数来获取父组件并订阅父组件的Disposed事件。 So when the parent component (eg form) is disposed, this object gets disposed as well: 因此,当处理父组件(例如表单)时,此对象也会被处置:

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

(I'd throw out the finalizer as an option because there's no telling if/when it's going to run.) (我会把终结器作为一个选项扔出去,因为无法确定是否/什么时候会运行。)

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

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