?
Solved

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

Posted on 2009-06-29
9
Medium Priority
?
264 Views
Last Modified: 2012-05-07
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.
0
Comment
Question by:rangers99
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 2
9 Comments
 
LVL 8

Expert Comment

by:Nate Feinberg
ID: 24737547
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
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 24737957
@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
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 400 total points
ID: 24738114
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
Windows Server 2016: All you need to know

Learn about Hyper-V features that increase functionality and usability of Microsoft Windows Server 2016. Also, throughout this eBook, you’ll find some basic PowerShell examples that will help you leverage the scripts in your environments!

 
LVL 8

Expert Comment

by:Nate Feinberg
ID: 24739939
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
 
LVL 8

Expert Comment

by:Nate Feinberg
ID: 24739978
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
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 24740098
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
 
LVL 8

Assisted Solution

by:Nate Feinberg
Nate Feinberg earned 100 total points
ID: 24740571
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
 

Author Comment

by:rangers99
ID: 24743398
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
 

Author Closing Comment

by:rangers99
ID: 31597967
IdleMind
I tried out the sample code you posted and it does exactly what I require. Thanks.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question