+1 vote
by (180 points)
edited

I'm using Rebex FTP library (plain old FTP, no security needed). I'm working asynchronously, in a multi-threaded environment, so the code in my class looks pretty much like this:

public class MyDownloader : IDisposable
{
    private readonly Ftp ftp = new Ftp();
    private MemoryStream ms = new MemoryStream();

    public void Download()
    {
        // connect, login, etc.            
        object state = null;
        ftp.BeginGetFile("remote/path", ms, MyCallback, state);
    }

    private void MyCallback(IAsyncResult ar)
    {
        try
        {
            var size = ftp.EndGetFile(ar);
        }
        catch
        {
            // log, whatever
        }

    }

    public void Dispose()
    {
        // disconnect if needed
        ftp.Dispose();
    }
}

The Questions

Let's say that there's a so-called race between 2 threads: Thread A calls the Dispose method in my class, and Thread B invokes the callback method (MyCallback) on the same time.

  1. Should I write my own mechanism for checking the state of my class (disposed or not)?
  2. Is it possible that after calling FTP's Dispose method, my class' MyCallback method will be executed at all?

Thanks!

Applies to: Rebex FTP/SSL

2 Answers

+1 vote
by (70.2k points)
edited
 
Best answer

To 1.) If the Ftp object was disposed before finishing the BeginXXX method, an FtpException is thrown when calling the EndXXX method. If the Ftp object was disposed after finishing the BeginXXX method, call of the EndXXX method will succeed without an exception. I suggest you to add the following catch to handle ObjectDisposedException in this case:

catch (FtpException ex)
{
    if (ex.Status == FtpExceptionStatus.AsyncError && ex.InnerException != null && ex.InnerException is ObjectDisposedException)
        // handle background ObjectDisposedException
}

To 2.) Ones the BeginXXX method was successfully called, the callback method will be executed always (even the object has been already disposed). If an exception occurred during the background operation, calling the EndXXX method will throw an FtpException with the FtpExceptionStatus.AsyncError.

by (180 points)
edited

I understand your answer, but it raises another question: Regarding the BeginGetFile method of the Ftp class - is it thread-safe? I mean, if two different threads invoke BeginGetFile and Dispose methods - is there a race?

+1 vote
by (70.2k points)
edited

The whole Ftp class is thread safe. Let suppose 3 cases:

  1. thread A invokes BeginGetFile, then thread B invokes Dispose (in next instruction). Result: no data are transferred and a callback is executed. Calling the EndGetFile method throws an FtpException as described in the previous answer.
  2. thread B invokes Dispose, then thread A invokes BeginGetFile (in next instruction). Result: calling the BeginGetFile method in thread A throws an ObjectDisposedException.
  3. thread A invokes BeginGetFile, then thread B also invokes BeginGetFile. Result: calling the BeginGetFile method in thread B throws an FtpException with the FtpExceptionStatus.Pending. Thread A will continue and data will be transferred.
by (180 points)
edited

Thanks! :-)

...