开发者

Best pattern for "Do some work and quit"

I'm currently writing a little GUI program that does some work and exits afterwards. While work is done, the GUI thread is updated with infos for the user.

This is the pattern I'm currently using and I'm thinking it's not the most elegant one:

static void MainForm_Loaded(BeoExport exporter)
{
    // Thread 1 runs the Export
    workerThread = new Thread(() =>
    {
        exporter.StartExport();
        // don't exit immediately, so the user sees someting if the work is done fast
        Thread.Sleep(1000);     
    });

    // Thread 2 waits for Thread 1 and exits the program afterwards
    waiterThread = new Thread(() =>
    {
        workerThread.Join();
        Application.Exit();
    });

    workerThread.Start();
    waiterThread.Start();
}

So what pattern/mechanics would you use to do the same?

To clarify: I was not interested in a way to update the GUI开发者_如何学Go thread. That's already done. This might sound esoteric but I was lookig for the right way to quit the application.

If I could, I would give Dave the credits, since he pointed out the usefulness of the BackgroundWorker.


Have you considered a BackgroundWorker thread instead? You can use its ReportProgress method and ProgressChanged event to update the GUI (with a progress bar perhaps), assuming that you can refactor BeoExport.StartExport method to also report progress. This gives the users visible feedback that work is actually happening.


I don't understand why do you use two threads. You can use threadpool:

ThreadPool.QueueUserWorkItem((state)=>{
    exporter.StartExport();
    Thread.Sleep(1000);
    Application.Exit();
});


I suggest you to use the BackgroundWorker class. It's thought to do the kind of job you're doing. You could do domething like this:

public class Form1 : Form
{
    private BackgroundWorker worker;
    private ProgressBar bar;
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        bar= new ProgressBar();
        bar.Dock = DockStyle.Top;
        Controls.Add(bar);

        worker = new BackgroundWorker();
        worker.WorkerReportsProgress=true;
        worker.RunWorkerCompleted += delegate
                                         {
                                             Close();
                                         };
        worker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs ev)
                                      {
                                          bar.Value = ev.ProgressPercentage;
                                      };
        worker.DoWork += worker_DoWork;
        worker.RunWorkerAsync();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //do your work here. For the example, just sleep a bit 
        //and report progress
        for (var i = 0; i < 100;i++ )
        {
            Thread.Sleep(50);
            worker.ReportProgress(i);
        }
    }

}


You can use an AutoResetEvent. The main thread waits for the autoreset event to be reset.

var wh = new AutoResetEvent(false);

var workerThread = new Thread(() =>
{
    exporter.StartExport();
    // don't exit immediately, so the user sees something if the work is done fast
    Thread.Sleep(5000);
    wh.Set();
});

workerThread.Start();
wh.WaitOne();

Application.Current.Shutdown();


Have you taken a look at the Task Parallel Library in .net 4 you can set up a task and the library will work out to best pararellise it for you, either threading, working a seperate CPU core's the is a load of great information about it online.

Regards

Iain


To add a little to Lain's answer, here's a Console sample using a Task from the System.Threading.Tasks namespace.

 class Program
    {
        static void Main(string[] args)
        {

            Task<int> task  = Task<int>.Factory.StartNew(() =>
                {
                    Exporter exporter = new Exporter();
                    int i = exporter.StartExport();
                    return i;
                 });

            int iResult = task.Result;
            Console.WriteLine(iResult);
            Console.ReadLine();


        }

        class Exporter {
            public int StartExport()
            {
                //simulate some work
                System.Threading.Thread.Sleep(500);
                return 5;
            }
        }
    }


Using a BackgroundWorker might help you implement your background processing. If you wanted to stick with your current pattern then consider the following.

static void MainForm_Loaded(BeoExport exporter) 
{ 
    workerThread = new Thread(() => 
    { 
        exporter.StartExport(); 
        Thread.Sleep(1000);      
        MainForm.BeginInvoke(
          (Action)(() =>
          {
            MainForm.Close();
          });
    });
    workerThread.IsBackground = true;
    workerThread.Start();
} 


Have the worker thread send a notification message of some description to the main thread. The GUI can then either exit or display a "done" message as appropriate.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜