Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait for thread to complete without blocking UI

I want my program to wait after below line

frmProgressBarObj = PullMSI.ExtractByMSIName("products.txt", false);

as above method is internally calling thread through StartProcessWithProgress() method . I want that thread to be completed before //code logic -2 line gets executed. At the same time, It should not stop UI update done by frmProgressBar.UpdateProgress(). How do I do this?

namespace NS1
{
    public partial class frmMain : Form
    {                
        private void button1_Click(object sender, EventArgs e)
        {
            frmProgressBar frmProgressBarObj = PullMSI.ExtractByMSIName("products.txt", false);
            //code logic - 2
            MessageBox.Show("This is executing immediately. 
                             I want to wait until above thread is complete");
        }
    }

    public partial class frmProgressBar : Form
    {

        public void UpdateProgress(String strTextToDisplayOnProgress)
        {
            progressBar1.BeginInvoke(
                   new Action(() => 
                   { 
                       progressBar1.Value++; 
                       lblFileName.Text = strTextToDisplayOnProgress;
                       if (progressBar1.Value == progressBar1.Maximum)
                       {
                           this.Hide(); 
                        } 
                    }));
        }

        public delegate void DelProgress();

        public void StartProcessWithProgress(DelProgress delMethodCode, int maxCount)
        {
            InitializeProgress(maxCount);
            Thread backgroundThread = new Thread(new ThreadStart(delMethodCode));
            backgroundThread.Start();
        }
    }

    public static class PullMSI
    {
        public static frmProgressBar ExtractByMSIName(String strProductFilePath, bool reNameMSI)
        {
            frmProgressBar frmProgressBar = new frmProgressBar();

            frmProgressBar.StartProcessWithProgress(() =>
            {
                //StreamRader sr declaration and other code

                while (!sr.EndOfStream)
                {
                    //logic here
                    frmProgressBar.UpdateProgress("Copying sr.msiname");
                }
            }, 2);

            return frmProgressBar;
        }
    }
}
like image 665
Ashif Nataliya Avatar asked Jul 01 '15 12:07

Ashif Nataliya


People also ask

How to prevent UI from running in a temporary thread?

Perhaps you should simply prevent UI from some action until your temporary thread's work is complete. But this is very simple task: you should invoke change of UI status in the very beginning and the very end of the thread's body, that is in the same thread, not too different threads.

Is it bad to make the main thread wait for something?

First, you should never make main thread (which is your UI thread I assume) to wait for anything. Not only this is bad, this is also never needed. You code sample makes no sense at all, because the method of your thread really does nothing. Think of what are you doing.

Does doworkonuitrhead block the UI thread?

As you can see in the output, the tasks are run on an other thread, so they don’t block the UI thread, but they are run synchronously (one after the other). DoWorkOnUiTrhead started at [2012-11-16 11:55:59.116] on Thread [17].

How do I pass code to a thread in a UI?

Different UI frameworks provide different mechanisms for doing this, but in .NET they all take basically the same shape, a BeginInvoke method you can use to pass some code as a message to the UI thread to be processed:


1 Answers

I'm very surprised you haven't worked with any of these before but I would really recommend reading about threading in C# since it's fundamentally important to understand the intricacies and learning the language.

Below are three different ways you can achieve what you want:

1. Using reset events (further reading: https://msdn.microsoft.com/en-us/library/system.threading.manualreseteventslim(v=vs.110).aspx). If your C# version doesn't have the ManualResetEventSlim, replace it with ManualResetEvent and change Wait() with WaitOne()

class LockingWithResetEvents
{
    private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);

    public void Test()
    {
        MethodUsingResetEvents();
    }

    private void MethodUsingResetEvents()
    {
        ThreadPool.QueueUserWorkItem(_ => DoSomethingLong());
        ThreadPool.QueueUserWorkItem(_ => ShowMessageBox());
    }

    private void DoSomethingLong()
    {
        Console.WriteLine("Doing somthing.");
        Thread.Sleep(1000);
        _resetEvent.Set();
    }

    private void ShowMessageBox()
    {
        _resetEvent.WaitOne();
        Console.WriteLine("Hello world.");
    }
}

2) Using Task Parallel Library (TPL). Further reading: https://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx

class LockingWithTPL
{
    public void Test()
    {
        Task.Factory.StartNew(DoSomethingLong).ContinueWith(result => ShowMessageBox());
    }

    private void DoSomethingLong()
    {
        Console.WriteLine("Doing somthing.");
        Thread.Sleep(1000);
    }

    private void ShowMessageBox()
    {
        Console.WriteLine("Hello world.");
    }
}

3) Using Async/Await. Further reading: https://msdn.microsoft.com/en-us/library/hh191443.aspx

class LockingWithAwait
{
    public void Test()
    {
        DoSomething();
    }

    private async void DoSomething()
    {
        await Task.Run(() => DoSomethingLong());
        ShowMessageBox();
    }

    private async void DoSomethingLong()
    {
        Console.WriteLine("Doing somthing.");
        Thread.Sleep(10000);
    }

    private void ShowMessageBox()
    {
        Console.WriteLine("Hello world.");
    }
}

Also good to know: Mutex (https://msdn.microsoft.com/en-us/library/system.threading.mutex(v=vs.110).aspx), Semaphore (https://msdn.microsoft.com/en-us/library/system.threading.semaphore(v=vs.110).aspx), Lock (https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx), SemaphoreSlim (https://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim(v=vs.110).aspx), Monitor (https://msdn.microsoft.com/en-us/library/system.threading.monitor(v=vs.110).aspx) and Interlocked (https://msdn.microsoft.com/en-us/library/system.threading.interlocked(v=vs.110).aspx).

like image 70
kha Avatar answered Oct 03 '22 23:10

kha