![]() |
| | #1 |
| Registered User Join Date: Jun 2003
Posts: 90
| Passing data between a thread and a form
__________________ He who asks is a fool for five minutes, but he who does not ask remains a fool forever. The fool wonders, the wise man asks. - Benjamin Disraeli There are no foolish questions and no man becomes a fool until he has stopped asking questions. Charles Steinmetz |
| DanFraser is offline | |
| | #2 |
| and the Hat of Ass Join Date: Dec 2007
Posts: 810
| This should help, Dan. |
| rags_to_riches is offline | |
| | #3 |
| Sweet Join Date: Aug 2002 Location: Tucson, Arizona
Posts: 1,697
| You will need to implement a delegate. Then in your thread Invoke that delegate. Here is a quick example. This is using a progress bar but the concept is the same. Code: public partial class Form1 : Form
{
/// <summary>
/// Delegate function to use for progess bar update(This would be what method you would want to call)
/// </summary>
/// <param name="progress">The current progress of updates</param>
private delegate void ProgessUpdateDelegate(int progress);
/// <summary>
/// The thread for the progress update.
/// </summary>
private Thread mProgressThread;
/// <summary>
/// The delegated method for updating progess
/// </summary>
private ProgessUpdateDelegate mProgessDelegate;
public Form1()
{
InitializeComponent();
//Create the delegate for the progress update.
this.mProgessDelegate = new ProgessUpdateDelegate(this.UpdateProgressBar);
}
/// <summary>
/// This is the function you would be updating the text.
/// </summary>
private void UpdateProgressBar(int curentProgress)
{
//Update the progress value.
this.progressBar.Value = curentProgress;
}
private void btnStartThread_Click(object sender, EventArgs e)
{
//
//Create the thread and start it up.
//
mProgressThread = new Thread(new ThreadStart(this.StartFunctionWithProgress));
mProgressThread.Start();
}
/// <summary>
/// This would be the function where you are threading.
/// </summary>
private void StartFunctionWithProgress()
{
//
//Function that involves proccessing. Simulating with thread sleeps.
//
//
//Note: This is where you callback to update the UI.
//
Thread.Sleep(100);
this.Invoke(this.mProgessDelegate, 20);
Thread.Sleep(100);
this.Invoke(this.mProgessDelegate, 50);
Thread.Sleep(100);
this.Invoke(this.mProgessDelegate, 100);
}
}
__________________ Woop? |
| prog-bman is offline | |
| | #4 |
| Registered User Join Date: Aug 2008
Posts: 188
| i'd recommend using BeginInvoke over Invoke. sooner or later you'll run into a deadlock if u use the synchronous version. |
| bling is offline | |
| | #5 |
| Registered User Join Date: Jun 2003
Posts: 90
| Thanks guys, two great examples.
__________________ He who asks is a fool for five minutes, but he who does not ask remains a fool forever. The fool wonders, the wise man asks. - Benjamin Disraeli There are no foolish questions and no man becomes a fool until he has stopped asking questions. Charles Steinmetz |
| DanFraser is offline | |
| | #6 | |
| Registered User Join Date: May 2003
Posts: 1,199
| Quote:
By the way, Dan, this is a common way you'll see this done. It's in fact my code that does the exact thing you're trying to do: Code: private delegate void UpdateStatusHandler(string msg);
public void UpdateStatus(string str)
{
if (InvokeRequired)
BeginInvoke(new UpdateStatusHandler(UpdateStatus), new object[] { str });
else
{
toolStripStatusLabel1.Text = str;
}
}
Use Invoke() instead of BeginInvoke() if you want to wait for the function to complete before the worker thread continues.
__________________ You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards. Last edited by Cat; 11-24-2008 at 06:17 PM. | |
| Cat is offline | |
| | #7 |
| Sweet Join Date: Aug 2002 Location: Tucson, Arizona
Posts: 1,697
| Also as a side note. When dealing with params you don't need to create the array yourself. This is handled by the compiler so you can just pass it the arguments you want from Invoke or BeginInvoke. Example updated the StartFunctionWithProgess Code: public partial class Form1 : Form
{
/// <summary>
/// Delegate function to use for progess bar update(This would be what method you would want to call)
/// </summary>
/// <param name="progress">The current progress of updates</param>
private delegate void ProgessUpdateDelegate(int progress, string someValue);
/// <summary>
/// The thread for the progress update.
/// </summary>
private Thread mProgressThread;
/// <summary>
/// The delegated method for updating progess
/// </summary>
private ProgessUpdateDelegate mProgessDelegate;
public Form1()
{
InitializeComponent();
//Create the delegate for the progress update.
this.mProgessDelegate = new ProgessUpdateDelegate(this.UpdateProgressBar);
}
/// <summary>
/// This is the function you would be updating the text.
/// </summary>
private void UpdateProgressBar(int curentProgress, string someValue)
{
//Update the progress value.
this.progressBar.Value = curentProgress;
MessageBox.Show(someValue);
}
private void btnStartThread_Click(object sender, EventArgs e)
{
//
//Create the thread and start it up.
//
mProgressThread = new Thread(new ThreadStart(this.StartFunctionWithProgress));
mProgressThread.Start();
}
/// <summary>
/// This would be the function where you are threading.
/// </summary>
private void StartFunctionWithProgress()
{
//
//Function that involves proccessing. Simulating with thread sleeps.
//
//
//Note: This is where you callback to update the UI.
//
Thread.Sleep(100);
this.Invoke(this.mProgessDelegate, 20, "Woop");
Thread.Sleep(100);
this.Invoke(this.mProgessDelegate, 50, "Coolness");
Thread.Sleep(100);
this.Invoke(this.mProgessDelegate, 100, "Dude");
}
}
__________________ Woop? |
| prog-bman is offline | |
| | #8 |
| Confused Join Date: Sep 2001 Location: Sweden
Posts: 3,125
| I suggest using a System.ComponentModel.BackgroundWorker if you want a working thread in the background.
__________________ MagosX.com Give a man a fish and you feed him for a day. Teach a man to fish and you feed him for a lifetime. |
| Magos is offline | |
| | #9 | |
| Registered User Join Date: Aug 2008
Posts: 188
| Quote:
check out this article: http://kristofverbiest.blogspot.com/...gininvoke.html | |
| bling is offline | |
| | #10 | |
| Registered User Join Date: May 2003
Posts: 1,199
| Quote:
* The main thread cannot block. Any code that absolutely needs to block gets moved out of the main thread. * A worker thread may block waiting on the main thread. * A worker thread may not block waiting on another worker thread. You're right, though, in that they're difficult criteria to code for, and I'm not always 100% successful in following those rules. In general, though, I try to do the following: * Main form owns the shared data, and is allowed to access it without blocking. * Worker threads shall either do atomic operations (Interlocked.whatever) or they need to Invoke/BeginInvoke. Often, atomic operations are sufficient, as Interlocked has quite a few nice tools in it, especially with Exchange and CompareExchange.
__________________ You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards. | |
| Cat is offline | |
| | #11 |
| Registered User Join Date: Aug 2008
Posts: 188
| i don't understand why you would go through all that trouble to ensure thread safety when all you need to do is use BeginInvoke instead of Invoke (not to mention performance increases as mentioned in the article i linked) also, your criteria for the GUI thread not blocking (and owning) objects has a major pitfall. as you probably know, foreach is not thread-safe, so if at the moment you are displaying data of a collection with a foreach, your worker thread adds or removes data from the collection, it'll throw an exception. EDIT: i see that this isn't a problem if you use Invoke after you update the collection. Last edited by bling; 11-25-2008 at 04:34 PM. |
| bling is offline | |
| | #12 | ||
| Registered User Join Date: May 2003
Posts: 1,199
| Quote:
Quote:
Also, if you really need to use locks on objects, you won't get any Invoke-related deadlocks as long as: 1. The main thread doesn't block on workers except waiting for a lock, (e.g. it won't block waiting for a thread to terminate or anything like that). 2. Worker threads likewise cannot block on other workers except waiting for a lock. 3. The worker in question releases all its locks before Invoke(). I'm not saying Invoke() is better than BeginInvoke() in all or even most cases. Sometimes, though, it's the right tool for the job.
__________________ You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards. Last edited by Cat; 11-25-2008 at 04:45 PM. | ||
| Cat is offline | |
| | #13 |
| Registered User Join Date: Jun 2003
Posts: 90
| Woah, I've created quite the discussion haven't I! The program is very simplistic really, the background worker thread is merely there because that is quite intensive and I do not want the UI to hang during its work. The program consists of a listview, a status bar, a menu control and two main classes. The worker thread just contains a loop that will sometimes want to change the status bar text just for some additional information.
__________________ He who asks is a fool for five minutes, but he who does not ask remains a fool forever. The fool wonders, the wise man asks. - Benjamin Disraeli There are no foolish questions and no man becomes a fool until he has stopped asking questions. Charles Steinmetz |
| DanFraser is offline | |
| | #14 |
| Registered User Join Date: Aug 2008
Posts: 188
| lol, i think we can agree to disagree :P actually, you steered me into diving deeper into the code. if you check the call stack of the invoked method it's the same for both the Invoke and BeginInvoke variants, which means the only difference is the Invoke is calling EndInvoke for you. Last edited by bling; 11-25-2008 at 05:20 PM. |
| bling is offline | |
| | #15 |
| Registered User Join Date: May 2003
Posts: 1,199
| Guess we can agree on that much ![]() Anyhow, though, one final clarification of mine -- the "main thread never blocks" isn't just to avoid deadlocks. Its main point relates to one of my two major pet peeves: when the GUI becomes nonresponsive. I don't let the GUI thread block because I don't want the GUI to hang, under any condition, even if I only expect it to do so briefly. (My second pet peeve consists of applications that don't handle Unicode inputs, especially in the case of Unicode filenames. If the file has a legal filename on my operating system, you will support it in your software.)
__________________ You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards. |
| Cat is offline | |
![]() |
| Thread Tools | |
| Display Modes | |
|