thread safe calls
-
Hi, I posted this message earlier and some one posted a link to an article. It helped, but still I am confused how to do it in my scenario. I have a HomeForm (main form which has main()). In one of its meathod I have
PrimeInfoThread pTh = new PrimeInfoThread(this.pictureBox1,this.panel4,this.button1,this.button3,this.SLabel); Thread t = new Thread(new ThreadStart(pTh.ThreadProc)); t.Start();
PrimeInfoThread is another class as followspublic class PrimeInfoThread { private System.Windows.Forms.PictureBox hPic ; private System.Windows.Forms.Panel hPan ; private System.Windows.Forms.Button but1 ; private System.Windows.Forms.Button but2 ; private System.Windows.Forms.Label slab ; // The constructor public PrimeInfoThread(System.Windows.Forms.PictureBox hP, System.Windows.Forms.Panel hpanel, System.Windows.Forms.Button b1, System.Windows.Forms.Button b2, System.Windows.Forms.Label Sl) { hPic = hP; hPan = hpanel; but1 = b1; but2 = b2; slab = Sl; } public void ThreadProc() { EnumGetEDID InitEnumObj = new EnumGetEDID(); InitEnumObj.AppInitEnum(slab); hPic.Hide(); hPan.Hide(); but1.Show(); but2.Show(); } }
In threadProc I call another class EnumGetEDID and call AppInitEnum(slab) where I pass the label. Inside AppInitEnum() I do 'slab.Text' to set the text values. Now how do I make this Thread safe. Can anyone show it in my code. Thanks a lot. -
Hi, I posted this message earlier and some one posted a link to an article. It helped, but still I am confused how to do it in my scenario. I have a HomeForm (main form which has main()). In one of its meathod I have
PrimeInfoThread pTh = new PrimeInfoThread(this.pictureBox1,this.panel4,this.button1,this.button3,this.SLabel); Thread t = new Thread(new ThreadStart(pTh.ThreadProc)); t.Start();
PrimeInfoThread is another class as followspublic class PrimeInfoThread { private System.Windows.Forms.PictureBox hPic ; private System.Windows.Forms.Panel hPan ; private System.Windows.Forms.Button but1 ; private System.Windows.Forms.Button but2 ; private System.Windows.Forms.Label slab ; // The constructor public PrimeInfoThread(System.Windows.Forms.PictureBox hP, System.Windows.Forms.Panel hpanel, System.Windows.Forms.Button b1, System.Windows.Forms.Button b2, System.Windows.Forms.Label Sl) { hPic = hP; hPan = hpanel; but1 = b1; but2 = b2; slab = Sl; } public void ThreadProc() { EnumGetEDID InitEnumObj = new EnumGetEDID(); InitEnumObj.AppInitEnum(slab); hPic.Hide(); hPan.Hide(); but1.Show(); but2.Show(); } }
In threadProc I call another class EnumGetEDID and call AppInitEnum(slab) where I pass the label. Inside AppInitEnum() I do 'slab.Text' to set the text values. Now how do I make this Thread safe. Can anyone show it in my code. Thanks a lot.It seems to me that you're making this more complicated than it needs to be with the use of an entirely seperate class (
PrimeInfoThread
) to run your other thread. Why don't you just have a method in yourHomeForm
class calledThreadProc()
and then reference the UI components (labels, buttons, etc...) without passing them to another object. You can use theParameterizedThreadStart
delegate to pass the label 'slab
' - although it might make more sense to just pass the string value of itsText
property if thats the only reason you need it... If you do that, then the following code should make it thread safe... This goes in the routine that starts the thread:Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
t.Start(this.SLabel);Then this in
HomeForm
:private void ThreadProc(object data)
{
EnumGetEDID InitEnumObj = new EnumGetEDID();
InitEnumObj.AppInitEnum((Label)data);
UpdateUI();
}private delegate void UpdateUIDelegate();
private void UpdateUI()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new UpdateUIDelegate(UpdateUI));
return;
}
pictureBox1.Hide();
panel4.Hide();
button1.Show();
button3.Show();
}Hope this helps :) Oh... forgot to say that this uses .Net Framework v2, since the
ParameterizedThreadStart
delegate isn't available in v1.1 :doh: Cheers, Will H -- modified at 15:41 Thursday 2nd February, 2006 -
It seems to me that you're making this more complicated than it needs to be with the use of an entirely seperate class (
PrimeInfoThread
) to run your other thread. Why don't you just have a method in yourHomeForm
class calledThreadProc()
and then reference the UI components (labels, buttons, etc...) without passing them to another object. You can use theParameterizedThreadStart
delegate to pass the label 'slab
' - although it might make more sense to just pass the string value of itsText
property if thats the only reason you need it... If you do that, then the following code should make it thread safe... This goes in the routine that starts the thread:Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
t.Start(this.SLabel);Then this in
HomeForm
:private void ThreadProc(object data)
{
EnumGetEDID InitEnumObj = new EnumGetEDID();
InitEnumObj.AppInitEnum((Label)data);
UpdateUI();
}private delegate void UpdateUIDelegate();
private void UpdateUI()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new UpdateUIDelegate(UpdateUI));
return;
}
pictureBox1.Hide();
panel4.Hide();
button1.Show();
button3.Show();
}Hope this helps :) Oh... forgot to say that this uses .Net Framework v2, since the
ParameterizedThreadStart
delegate isn't available in v1.1 :doh: Cheers, Will H -- modified at 15:41 Thursday 2nd February, 2006 -
If you use the 2.0, try to use the BackgroundWorker, it gives the abilty to update without the cross-thread exception.
-
If you use the 2.0, try to use the BackgroundWorker, it gives the abilty to update without the cross-thread exception.
I just gave the
BackgroundWorker
class a whirl, and I don't think it does allow you to update the UI from a seperate thread. Maybe I miss-read your meaning, but I took the C# code from the example in the MSDN library (here[^]), then I added the linethis.Text = percentComplete + "%";
just afterworker.ReportProgress(percentComplete);
in theComputeFibonacci
method (the one that's running on the seperate thread), and this caused a System.InvalidOperationException - a cross thread exception :confused: Cheers, Will H -
I just gave the
BackgroundWorker
class a whirl, and I don't think it does allow you to update the UI from a seperate thread. Maybe I miss-read your meaning, but I took the C# code from the example in the MSDN library (here[^]), then I added the linethis.Text = percentComplete + "%";
just afterworker.ReportProgress(percentComplete);
in theComputeFibonacci
method (the one that's running on the seperate thread), and this caused a System.InvalidOperationException - a cross thread exception :confused: Cheers, Will HYou can only update UI controls on the thread that created them. Property updates and method calls on those controls must be marshalled back onto the UI thread. Lookup
Control.Invoke
for more information. RageInTheMachine9532 "...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome -
I just gave the
BackgroundWorker
class a whirl, and I don't think it does allow you to update the UI from a seperate thread. Maybe I miss-read your meaning, but I took the C# code from the example in the MSDN library (here[^]), then I added the linethis.Text = percentComplete + "%";
just afterworker.ReportProgress(percentComplete);
in theComputeFibonacci
method (the one that's running on the seperate thread), and this caused a System.InvalidOperationException - a cross thread exception :confused: Cheers, Will HTo update GUI with the BackgroundWorker, you need to do the following steps: 1. When creating the wroker: public void InitWorker() { worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); worker.DoWork += new DoWorkEventHandler(worker_DoWork); } Note that I've creating new event handler to update GUI, when ever I want to set something on the GUI, I should call the ReportProgress(...) method of the worker: void worker_DoWork(object sender, DoWorkEventArgs e) { // Some long operation // ..... Thread.Sleep(2000); // Update GUI worker.ReportProgress(30); // Some long operation // ..... Thread.Sleep(2000); // Update GUI worker.ReportProgress(60); // Some long operation // ..... Thread.Sleep(2000); // Update GUI worker.ReportProgress(90); } And, on the ReportProgress handler, I can update the GUI as I want, this is beacuse the worker handles moving the OS the the right thread so it is not my problem... void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { Label label; label.Text = e.ProgressPercentage + "%"; } Note that on the ReportProgress you can send an object that will be set on the ProgressChangedEventArgs (State), in this property you can set all the values you want to update on the GUI (other than the precentage).
-
You can only update UI controls on the thread that created them. Property updates and method calls on those controls must be marshalled back onto the UI thread. Lookup
Control.Invoke
for more information. RageInTheMachine9532 "...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome -
To update GUI with the BackgroundWorker, you need to do the following steps: 1. When creating the wroker: public void InitWorker() { worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged); worker.DoWork += new DoWorkEventHandler(worker_DoWork); } Note that I've creating new event handler to update GUI, when ever I want to set something on the GUI, I should call the ReportProgress(...) method of the worker: void worker_DoWork(object sender, DoWorkEventArgs e) { // Some long operation // ..... Thread.Sleep(2000); // Update GUI worker.ReportProgress(30); // Some long operation // ..... Thread.Sleep(2000); // Update GUI worker.ReportProgress(60); // Some long operation // ..... Thread.Sleep(2000); // Update GUI worker.ReportProgress(90); } And, on the ReportProgress handler, I can update the GUI as I want, this is beacuse the worker handles moving the OS the the right thread so it is not my problem... void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { Label label; label.Text = e.ProgressPercentage + "%"; } Note that on the ReportProgress you can send an object that will be set on the ProgressChangedEventArgs (State), in this property you can set all the values you want to update on the GUI (other than the precentage).
-
It doesn't "get around it". It just fire an event on the correct thread. It insulates you from the details of getting code that modifies a UI control to run on the correct thread. RageInTheMachine9532 "...a pungent, ghastly, stinky piece of cheese!" -- The Roaming Gnome