Main Thread calls a new Thread. How Do I Synchronise when new thread is finished?

Im developing a windows application (not Internet based)  using Visual Studio 2008 and Visual C#.

The application basically reads the output from some  hardware then processes the information and draws graphs etc. The part where it reads infomation from the hardware can take up to ten minutes and basically locks up the computer. I want to have this bit in a separate thread so it can be aborted if necessary and so the computer can do other things.

When the user clicks a button the following code is executed on the Main Thread.
 
'threadTask' is the function that reads from the hardware and is the executed from the new thread.

  Thread trd = new Thread(new ThreadStart(this.threadTask));
   trd.IsBackground = true;
   trd.Start();

Now when this function finishes I want this thread to basically end and another function (that processes  the information) to start executing. This function (lets call it Process) should in the Main thread.

How do I synchronise so that the function Process on the Main thread is executed when the thread I created to read from the hardware (the function threadTask) is finished?

Note all the data is stored in class variables so I dont need to send data as function arguments etc.
rangers99Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Nate FeinbergFinancial Center Operations ManagerCommented:
You could have a central locking sync object. Take this for example. The "lock" statement attempts to acquire an exclusive "lock" on an object (make sure one exists, though--null should throw an exception). If a lock has already been acquired on an object, it will wait until unlocked.
You could also use the Monitor class for more "finite" control over your thread sync'ing. I'll provide a link for that, as it is not really imperative.
http://msdn.microsoft.com/en-us/library/system.threading.monitor.aspx 
Hope it helps,
Nate

// Inside main class
private Object sync = new Object();
 
// "Main" thread--method that initiates everything
private void MainWorkHandler()
{
     Thread t = new Thread(this.threadTask);
     t.IsBackground = true;
     t.Start();
     lock(sync)
     {
          // Draw your grahps and such; the other thread is done
     }
}
private void threadTask()
{
     lock(sync)
     {
          // Get the information from the hardware
     }
}

Open in new window

0
Mike TomlinsonMiddle School Assistant TeacherCommented:
@InternalStatic...wouldn't that be counter-productive?...

The author states:

    "The part where it reads infomation from the hardware can take up to ten minutes..."

So threadTask() will lock "sync" and then start performing its task...which could take "up to ten minutes", and keep "sync" locked until it completes.

Meanwhile, the main thread will also attempt to lock "sync", but will fail because threadTask() already has it.  This will result in the main thread BLOCKING until "sync" has been released:
http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.80).aspx

    "If another thread attempts to enter a locked code, it will wait, block, until the object is released."

End result will be a completely unresponsive GUI.
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
To answer this question:

    "How do I synchronise so that the function Process on the Main thread is executed when the thread I created to read from the hardware (the function threadTask) is finished?"

I would think a simple "this.Invoke()" would do the trick:
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private delegate void ProcessDataDelegate();
 
        private void button1_Click(object sender, EventArgs e)
        {
            Thread trd = new Thread(new ThreadStart(this.threadTask));
            trd.IsBackground = true;
            trd.Start();
        }
 
        private void threadTask()
        {
            // ...simulated processing...
            System.Threading.Thread.Sleep(Convert.ToInt32(TimeSpan.FromSeconds(10).TotalMilliseconds));
 
            this.Invoke(new ProcessDataDelegate(ProcessData));
        }
 
        private void ProcessData()
        {
            // ...this is now back on the main UI thread...
 
            this.label1.Text = "Processed data...";
        }
    }

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

Nate FeinbergFinancial Center Operations ManagerCommented:
Idle_Mind: I'm pretty sure what he's saying is he needs the information from the hardware BEFORE the graphing and such can be done. From what I read from the question, I see nothing about illegal thread crossing exceptions or the like. He just wants the task to be done on a thread other than the window's message loop, in case he wishes to cancel the operation.
Author, is this correct, or am I missing the point?
Nate
0
Nate FeinbergFinancial Center Operations ManagerCommented:
I'm assuming that the data processing part is not time-consuming, which is why I put it on the same thread as the message loop. If this is not accurate, you should use this.Invoke for the data processing.
Hope this helps,
Nate
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
I could be interpreting wrong too...can't ignore that possibility!   =)

I'll restate my concern differently though as I think you've missed an important detail.
 
The author is starting the secondary thread from a BUTTON click:

    "When the user clicks a button the following code is executed on the Main Thread."

...and your code has:

     // inside the button click handler
     ... start up secondary thread ...
     lock(sync)
     {
          // Draw your grahps and such; the other thread is done
     }

When the main UI hits "lock(sync)" it is going to BLOCK until threadTask() completes (which could take up to ten minutes).  This is because the "sync" object has already been locked by the secondary thread.

So what you've essentially done is created a completely locked up main thread.  It won't respond to user interaction and will not paint correctly resulting in the commonly seen "white out" symptom.

The approach you've given is a perfectly valid one for synchronizing threads...it's just not the best choice when one of those threads is the main UI thread!  ;)

A key difference between mine and yours is that you've attempted to keep the "flow" of the code INSIDE the same method that started the secondary thread while I have seperated it out so that a DIFFERENT method is executed once the secondary thread has completed.
0
Nate FeinbergFinancial Center Operations ManagerCommented:
Hmm, yeah I didn't think about it that way--I always assume more complexity than is necessarily present ;)
Idle_Mind is right, you should probably have the other lock statement lock on a thread other than the UI thread--otherwise, re-paint messages and such won't be sent to the window. You can edit the code as follows to "free up" the UI thread, while still maintaining the sync.
There are obviously a ton of ways to do this, so if any of these ways don't work, we'll need some more details.
Hope it helps, and thanks Idle_Mind,
Nate

// Inside main class
private Object sync = new Object();
 
// "Main" thread--method that initiates everything
private void MainWorkHandler()
{
     Thread t = new Thread(this.threadTask);
     t.IsBackground = true;
     t.Start();
     new Thread(ProcessData).Start();
}
private void threadTask()
{
     lock(sync)
     {
          // Get the information from the hardware
     }
}
private void ProcessData(Object ignore)
{
     lock(sync)
     {
          // Process your data in whatever way you wish
     }
}

Open in new window

0
rangers99Author Commented:
Nate said:

"Idle_Mind: I'm pretty sure what he's saying is he needs the information from the hardware BEFORE the graphing and such can be done. From what I read from the question, I see nothing about illegal thread crossing exceptions or the like. He just wants the task to be done on a thread other than the window's message loop, in case he wishes to cancel the operation.

Author, is this correct, or am I missing the point?"


Yes Nate that correct.

Thanks for all the replies. Im going to read through them all now!
0
rangers99Author Commented:
IdleMind
I tried out the sample code you posted and it does exactly what I require. Thanks.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.