views:

693

answers:

6

I have to be able to save a file, unfortunatly it can potentially be very large so saving it can potentially take minutes. As I need to do this from a GUI thread I don't want to block the GUI from executing. I was thinking about attempting the save operation on a seperate thread to allow the primary GUI thread to continue executing.

Is there a nice (easy) way to spawn a new thread, save the file, and destroy the thread without any nasty side effects?!

It must be said that I have NEVER had to use threads before so I am a complete novice! Any and all help would be greatly appreciated!

+5  A: 

You could maybe use the BackGroundWorker component, as it will abstract a bit the Threading part for you.

Frederik Gheysels
+4  A: 

BackgroundWorker (as suggested by Frederik) is a good choice, particularly if you want to report progress to the UI while you're saving. A search for BackgroundWorker tutorial gets a lot of hits, so you should be able to follow one of those to get you started.

One thing to be careful of: would there be any way of changing the data structure that you'll be trying to save from the UI thread? If so, you should disable those aspects of the UI while you're saving - it would (probably!) be bad to be half way through saving the data, then allow the user to change some of it. If you can get away with effectively handing off the data to the background thread and then not touching it from the UI thread, that will make your life a lot easier.

Jon Skeet
I would think it would be better to make a copy of the data and hand that off to the background worker as opposed to disabling parts of the UI.
Quibblesome
@Quarrelsome: Sometimes. It really depends on the situation, and whether the user expects that the result will be a snapshot or not. Also in some cases taking a complete snapshot may be really hard to get right - it's better to have a reliable but slightly annoying program than a broken one :)
Jon Skeet
+2  A: 

Your problem might be that there are several nice and easy ways of doing it. If you just want to set off the file save and not worry about knowing when it has completed, then having a method

void SaveMyFile(object state)
{
    // SaveTheFile
}

and calling it with

ThreadPool.QueueUserWorkItem( SaveMyFile );

will do what you want.

amaca
A: 

or u could use old friends delegates.

+2  A: 

I would recommend doing Asynchronous I/O. It's a little bit easier to set up and doesn't require you to create new threads yourself.

Asynchronous programming is where you have, for example, a file stream you want to write to but does not want to wait for it to finish. You might want to be notified when it's finished but you don't want to wait.

What you do is using the BeginWrite/BeginRead and EndWrite/EndRead functions that are available on the Stream class.

In your method you start by calling BeginWrite with all the data you want to write and also pass in a callback function. This function will be called when BeginWrite has finished.

Inside the callback function you call EndWrite and clean up the stream and check for errors.

BeginWrite will not block which means that if it's called from within an event handler that thread can finish that handler and continue processing more event (such as other GUI events).

using System;
using System.IO;
using System.Text;

class Program
    {
        private static FileStream stream;
        static void Main(string[] args)
        {
            stream = new FileStream("foo.txt", 
                                    FileMode.Create, 
                                    FileAccess.Write);

            const string mystring = "Foobarlalala";
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] data = encoding.GetBytes(mystring);
            Console.WriteLine("Started writing");
            stream.BeginWrite(data, 0, data.Length, callback, null);
            Console.WriteLine("Writing dispatched, sleeping 5 secs");
            System.Threading.Thread.Sleep(5000);
        }

        public static void callback(IAsyncResult ia)
        {
            stream.EndWrite(ia);
            Console.WriteLine("Finished writing");
        }
    }
}

The sleeping is pretty important because the thread that's writing stuff will be killed if the main thread is killed off. This is not an issue in a GUI application, only here in this small example.

MSDN has a pretty good overview on how to write this stuff, and also some good articles on Asynch programming in general in case you go for the backgroundworker or ThreadPool.

Mats Fredriksson