简体   繁体   中英

Finishing up a thread loop after disposal

I am looking for thread safe code in C# that will avoid two issues if possible;

  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. Eg Correct finishing of server's thread

The thread is calling a method which has the following while loop;

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(). 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. 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(). How bad is this?

It doesn't look that bad. Once you set Finished=true . it should finish posting a new delegate and then exit the loop. However, you might run into CPU caching issues with Finished . 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. To prevent this, you should create a private field that is only modified via Interlocked , and a method that modifies that field:

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

and the loop would run 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. 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. 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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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