Solved

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

Posted on 2009-06-29
9
263 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: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 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 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
Turn Insights Into Action

You’ve already invested in ITSM tools, chat applications, automation utilities, and more. Fortify these solutions with intelligent communications so you can drive business processes forward.

With xMatters, you'll never miss a beat.

 
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 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: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

PeopleSoft Has Never Been Easier

PeopleSoft Adoption Made Smooth & Simple!

On-The-Job Training Is made Intuitive & Easy With WalkMe's On-Screen Guidance Tool.  Claim Your Free WalkMe Account Now

Question has a verified solution.

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

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…
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.
If you're a developer or IT admin, you’re probably tasked with managing multiple websites, servers, applications, and levels of security on a daily basis. While this can be extremely time consuming, it can also be frustrating when systems aren't wor…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

691 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