Solved

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

Posted on 2009-06-29
9
260 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
  • 4
  • 3
  • 2
9 Comments
 
LVL 8

Expert Comment

by:InternalStatic
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 85

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 85

Accepted Solution

by:
Mike Tomlinson earned 100 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
MIM Survival Guide for Service Desk Managers

Major incidents can send mastered service desk processes into disorder. Systems and tools produce the data needed to resolve these incidents, but your challenge is getting that information to the right people fast. Check out the Survival Guide and begin bringing order to chaos.

 
LVL 8

Expert Comment

by:InternalStatic
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:InternalStatic
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 85

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:InternalStatic
InternalStatic earned 25 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

Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

Question has a verified solution.

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

Suggested Solutions

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

828 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