C# thread called multiple times but runs once [duplicate] - c#

This question already has answers here:
WebBrowser Control in a new thread
(4 answers)
Closed 9 years ago.
Basically I have a form with a button, when the button is pressed it creates an instance of a class that runs a Thread. When the thread is done, it automatically calls Thread.Abort().
The code I currently have comes down to this:
Button:
private void Buttonclick(object sender, EventArgs e)
{
MyClass c = new MyClass()
c.Do_your_thing();
}
Class:
public class MyClass
{
Thread t;
public void Do_your_thing()
{
t = new Thread(Running_code);
t.Start();
}
private void Running_code()
{
//Perform code here
t.Abort();
}
}
When I click the button once, everything works. But when I press the button again, nothing happens.
When I don't use t.Abort() everything works. But not using t.Abort() will cause memory leaks and the program won't close properly (the thread is never closed, therefor the process will stay alive).
Can anyone explain me what is going on? And how can I fix it?
EDIT: as per request I am posting some actual code
public class MyClass
{
public void Test()
{
t = new Thread(() =>
{
wb.DocumentCompleted += get_part;
wb.Navigate("http://www.google.com");
Application.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public void get_part(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var br = sender as WebBrowser;
string url = e.Url.ToString();
//Here is some code that compares the url to surten predefined url. When there is a match, it should run some code and then go to a new url
if(url == string_final_url)
{
//Finally at the url I want, open it in a new Internet Explorer Window
Process proc = Process.Start("IExplore.exe", url);
}
}
}
This is a fraction of a little webscraper program. It navigates to a webpage that needs some login info. When I reached the page I actually want to be, he should open it in a new Internet Explorer.
When I call this code and close the form, it's still visible in the process tree. And when I click the button multiple times, the memory used keeps getting higher, which I suspected to be some sort of memory leak.

Firstly, don't use Thread.Abort(), ever. See Is this thread.abort() normal and safe? for more details on why.
There are many warnings all over the net about using Thread.Abort(). I would recommend avoiding it unless it's really needed, which in this case, I don't think it is. You'd be better off just implementing a one-shot timer, with maybe a half-second timeout, and resetting it on each keystroke. This way your expensive operation would only occur after a half-second or more (or whatever length you choose) of user inactivity.
Instead of using abort you can use the Join() Method. This method blocks the calling thread until a thread terminates.
An example of it use is
Thread t1 = new Thread(() =>
{
Thread.Sleep(4000);
Console.WriteLine("t1 is ending.");
});
t1.Start();
Thread t2 = new Thread(() =>
{
Thread.Sleep(1000);
Console.WriteLine("t2 is ending.");
});
t2.Start();
t1.Join();
Console.WriteLine("t1.Join() returned.");
t2.Join();
Console.WriteLine("t2.Join() returned.");
I hope this helps.
Edit. To address your comments; The call to Join() is what de-allocates the thread. You don't have to do anything else. Just make sure that the threads clean up any resources they might be using before they exit.
That said, I would urge you to look into using the thread pool or the Task Parallel Library (TPL) rather than explicitly managing threads. They're easier to use, and handle this kind of thing much more smoothly.

Are you able to utilize .net 4 + if so you can use the TPL which would greatly simpify this as
public class MyClass
{
public void Do_your_thing()
{
// for async execution
Task.Factory.StartNew(Running_code);
// for synchronous execution
// CAUTION !! If invoked from UI thread this will freeze the GUI until Running_code is returned.
//Task.Factory.StartNew(Running_code).Wait();
}
private void Running_code()
{
Thread.Sleep( 2000 );
Debug.WriteLine( "Something was done" );
}
}
Moreover if the Running_Code method was doing something IO bound the TPL can utilize the IO completion ports and the operation may be completely threadless.
EDIT:
Have a look at this SO thread. WebBrowser Control in a new thread.
Apparently webbrowser control does not play well with non UI threads.

Related

Which is the better practice: Multiple BackgroundWorkers or Change the DoWork to a different method? [duplicate]

Suppose you have a search textbox and have a search algorithm attached to the TextChanged event, that runs with a BackgroundWorker. If there comes a new character in the textbox, i need to cancel the previous search and run it again.
I tried using events in between the main thread and the bgw, from this previous question, but I still get the error "currently busy and cannot run multiple tasks concurrently"
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
private void txtSearch_TextChanged(object sender, EventArgs e)
{
SearchWithBgw();
}
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
void bgw_Search_DoWork(object sender, DoWorkEventArgs e)
{
Search(txtSearch.Text, e);
}
private void Search(string aQuery, DoWorkEventArgs e)
{
int i = 1;
while (i < 3) // simulating search processing...
{
Thread.Sleep(1000);
i++;
if (bgw_Search.CancellationPending)
{
_resetEvent.Set(); // signal that worker is done
e.Cancel = true;
return;
}
}
}
EDIT To reflect answers. DonĀ“t reuse the BackgroundWorker, create a new one:
private void SearchWithBgw()
{
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
bgw_Search = new BackgroundWorker();
bgw_Search.WorkerSupportsCancellation = true;
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
bgw_Search.RunWorkerAsync();
}
When the _resetEvent.WaitOne() call completes, the worker thread isn't actually done. It is busy returning from DoWork() and waiting for an opportunity to run the RunWorkerCompleted event, if any. That takes time.
There is no reliable way to ensure the BGW is completed in a synchronous way. Blocking on IsBusy or waiting for the RunWorkerCompleted event to run is going to cause deadlock. If you really want to use only one bgw then you'll have to queue the requests. Or just don't sweat the small stuff and allocate another bgw. They cost very little.
Create a new background worker if the old one exists.
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
Also I know you put fake code in, but you want to make sure you set _resetEvent when the code completes normally too.
Do not reuse a Backgroundworker. It is a cheap resource, it is not a Thread.
make sure your Bgw code stops, yours looks OK. The Bgw will release the Thread to the pool.
but in the mean time, create a new Task/Bgw for a new job.
You may want to unsubscribe your Completed event from the old Bgw.
I think you should consider not cancelling the background worker.
If you cancel requests and the user types faster than your server returns queries, he will not see suggestions until he is finished typing.
In interactive scenarios like this, It could be better to show responses that run behind with what the user's typing. Your user will know he can stop typing if the word he has in mind is your suggestions list.
This will be also better for your server when it is busy, because instead of many cancelled requests, who will cost something but that are ultimately not shown, there will be fewer requests whose response you actually use.
I ran into similar issues with (3d) rendering applications, where the beginner's mistake is to cancel and rerender on every mousemove. This lead to a lot of computation and little interactive feedback.

uses of creating a thread and Blocking UI

I have started a special course in multithreading but I have some fundamental issues I want to clear up. say I have a thread
Thread t1 = new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
IsCancel = false;
this.workProj.DoWorkWithRefSync(ref IsCancel);
});
t1.Start();
Followed by
while(t1.IsAlive)
{
}
or
t1.Join();
or
myAutoResetEvent.WaitOne(); // myAutoResetEvent.Set() called in thread when it finished processing
I am not sure but, this might not be a good example but looking forward to one.
I know that they are all some form of signaling from the background thread to inform the calling/UI thread that the work has completed.
But using them end up blocking the UI until the thread completes. So I would like to know a real life scenario implementation of this.
I am thinking why not just run this process on the UI thread since you don't mind blocking it.
Edit: In otherwords, I am looking for the real uses of these blocking elements such as thread.Join() etc
A real life scenario relevant to your example would be where the reference to the thread is stored in a member of the window class, and it gets checked or waited for if some event triggers such as closing the window or the application exiting.
pseudo code:
class Window
{
private Thread _thread = null;
public void OnButtonClick()
{
_thread = CreateAndStartThread();
}
public void OnCloseWindow()
{
if(null != _thread)
_thread.Wait();
}
}

Thread.Join in UI thread also blocking child thread

This may well be a dumb question and if this has already been answered elsewhere then I'd really appreciate it if someone could point me to it as my searching hasn't turned up anything definitive.
In a nutshell, my problem is that when I do childThread.Join() in the UI thread on a child thread which has been flagged to stop the childThread seems to block as well as the main thread so everything just hangs.
That the UI will block due to using Join is not a problem in and of itself at the moment since the childThread should finish in under a second after it's told to quit anyway.
This happens while I'm waiting for a thread running a repeating process to quit before I can run another method which returns some information but can't be run at the same time as the other process.
My Winforms application is integrating with a piece of usb hardware by pinvoking the C API for the hardware.
The hardware API has a method that will start off a process that will run indefinitely and repeatedly and rapidly callback with new information which I then need to pass to the UI.
This operation can be cancelled by another call to the hardware API which sets a flag the hardware can see so it knows to quit.
I've wrapped this C API with my own C# code, and within the wrapper I've had to spin out the start process call in another thread so that the activity doesn't block the UI.
Here are the edited highlights of roughly what I'm doing.
public class DeviceWrapper
{
Thread childThread = null;
void DeviceWrapper
{
//Set the callback to be used by the StartGettingInformation() process
PInvokeMethods.SetGetInformationCallback(InformationAcquiredCallback);
}
public void StartProcess()
{
childThread = new Thread(new ThreadStart(GetInformationProcess))
childThread.Start();
}
void GetInformationProcess()
{
PInvokeMethods.StartGettingInformation();
}
//This callback occurs inside the childThread
void InformationAcquiredCallback(Status status, IntPtr information)
{
//This callback is triggered when anything happens in the
//StartGettingInformation() method, such as when the information
//is ready to be retrieved, or when the process has been cancelled.
if(status == Status.InformationAcquired)
{
FireUpdateUIEvent();
}
//If the cancel flag has been set to true this will be hit.
else if(status == Status.Cancelled)
{
//Reset the cancel flag so the next operation works ok
PInvokeMethods.SetCancelFlag(false);
childThread.Abort();
}
}
//This method runs once, and can't run at the same time as GetInformationProcess
public string GetSpecificInformation()
{
//This triggers InformationAcquiredCallback with a status of Cancelled
StopProcess();
if(childThread.IsAlive)
{
childThread.Join();
}
return PInvokeMethods.GetSpecificInformation();
}
public void StopProcess()
{
PInvokeMethods.SetCancelFlag(true);
}
}
Using this code when I call childThread.Join() the whole application grinds to a halt (which I'd expect for the UI and that's fine) and the childThread also seems to halt because the callback never gets hit again.
However, if I use the following code instead:
public string GetSpecificInformation()
{
//This triggers InformationAcquiredCallback with a status of Cancelled
StopProcess();
string s = "";
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
if(childThread.IsAlive)
{
childThread.Join();
}
s = PInvokeMethods.GetSpecificInformation();
}));
return s;
}
Then everything gets hit as expected and childThread does finish and all is well, except obviously my string gets returned empty before the WaitCallback fires and assigns to it.
So, do I just have to suck it up and change the class so that I use the QueueUserWorkItem and WaitCallback and fire an event to deal with my string return?
Is there something daft I'm doing in my first approach that's causing the childThread to block as well?
Or is there another tactic or class entirely that I should be using, bearing in mind it's .NET 3.5 I'm on?
Well, FireUpdateUIEvent(); sounds like a method that might Post Send to the MsgQueue (Control.Invoke()). When the main thread is waiting in a Join() then you have a classic deadlock.
In Addition, childThread.Abort() is not considered safe.
So, do I just have to suck it up and change the class so that I use the QueueUserWorkItem and WaitCallback and fire an event to deal with my string return?
I certainly would re-design it. It probably can be simplified a bit.

Pausing a method for set # of milliseconds

I need to do a sort of "timeout" or pause in my method for 10 seconds (10000 milliseconds), but I'm not sure if the following would work as i do not have multi-threading.
Thread.Sleep(10000);
I will try to use that current code, but I would appreciate if someone could explain the best and correct way of doing this, especially if the above code does not work properly. Thanks!
UPDATE: This program is actually a console application that in the function in question is doing many HTTPWebRequests to one server, so I wish to delay them for a specified amount of milliseconds. Thus, no callback is required - all that is needed is an "unconditional pause" - basically just the whole thing stops for 10 seconds and then keeps going. I'm pleased that C# still considers this as a thread, so Thread.Sleep(...) would work. Thanks everybody!
You may not have multi-threading, but you're still executing within a thread: all code executes in a thread.
Calling Thread.Sleep will indeed pause the current thread. Do you really want it to unconditionally pause for 10 seconds, or do you want to be able to be "woken up" by something else happening? If you're only actually using one thread, calling Sleep may well be the best way forward, but it will depend on the situation.
In particular, if you're writing a GUI app you don't want to use Thread.Sleep from the UI thread, as otherwise your whole app will become unresponsive for 10 seconds.
If you could give more information about your application, that would help us to advise you better.
Thread.Sleep is fine, and AFAIK the proper way. Even if you are not Multithreaded: There is always at least one Thread, and if you send that to sleep, it sleeps.
Another (bad) way is a spinlock, something like:
// Do never ever use this
private void DoNothing(){ }
private void KillCPU()
{
DateTime target = DateTime.Now.AddSeconds(10);
while(DateTime.Now < target) DoNothing();
DoStuffAfterWaiting10Seconds();
}
This is sadly still being used by people and while it will halt your program for 10 seconds, it will run at 100% CPU Utilization (Well, on Multi-Core systems it's one core).
That will indeed pause the executing thread/method for 10 seconds. Are you seeing a specific problem?
Note that you shouldn't Sleep the UI thread - it would be better to do a callback instead.
Note also that there are other ways of blocking a thread that allow simpler access to get it going again (if you find it is OK after 2s); such as Monitor.Wait(obj, 10000) (allowing another thread to Pulse if needed to wake it up):
static void Main() {
object lockObj = new object();
lock (lockObj) {
new Thread(GetInput).Start(lockObj);
Monitor.Wait(lockObj, 10000);
}
Console.WriteLine("Main exiting");
}
static void GetInput(object state) {
Console.WriteLine("press return...");
string s = Console.ReadLine();
lock (state) {
Monitor.Pulse(state);
}
Console.WriteLine("GetInput exiting");
}
You can do this with Thread.Interrupt too, but IMO that is messier.
You could use a separate thread to do it:
ThreadPool.QueueUserWorkItem(
delegate(object state)
{
Thread.Sleep(1000);
Console.WriteLine("done");
});
But, if this is a Windows Forms app, you will need to invoke the code after the delay from the Gui thread (this article, for example: How to update the GUI from another thread in C#?).
[Edit] Just saw your update. If it's a console app, then this will work. But if you haven't used multiple threads so far, then you need to be aware that this code will be executed in a different thread, which means you will have to take care about thread synchronization issues.
If you don't need background workers, stick to "keeping it simple".
Here is a pause class that will pause for the desired milliseconds and wont consume your CPU resources.
public class PauseClass
{
//(C) Michael Roberg
//Please feel free to distribute this class but include my credentials.
System.Timers.Timer pauseTimer = null;
public void BreakPause()
{
if (pauseTimer != null)
{
pauseTimer.Stop();
pauseTimer.Enabled = false;
}
}
public bool Pause(int miliseconds)
{
ThreadPriority CurrentPriority = Thread.CurrentThread.Priority;
if (miliseconds > 0)
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
pauseTimer = new System.Timers.Timer();
pauseTimer.Elapsed += new ElapsedEventHandler(pauseTimer_Elapsed);
pauseTimer.Interval = miliseconds;
pauseTimer.Enabled = true;
while (pauseTimer.Enabled)
{
Thread.Sleep(10);
Application.DoEvents();
//pausThread.Sleep(1);
}
pauseTimer.Elapsed -= new ElapsedEventHandler(pauseTimer_Elapsed);
}
Thread.CurrentThread.Priority = CurrentPriority;
return true;
}
private void pauseTimer_Elapsed(object sender, ElapsedEventArgs e)
{
pauseTimer.Enabled = false;
}
}
Yes, that works just fine.
You don't have to have multiple threads to make use of some of the methods in the Thread class. You always have at least one thread.
For a timeout, you should have a static volatile boolean isRunning class field. When the new thread starts, the isRunning must become true, and at the end must become false.
The main thread should have a method that loops for the isRunning during the timeout you define. When the timeout ends, you should implement the logic. But, never use the abort thread method.
A pause... there isn't a straightforward solution. It depends on what you are doing inside the thread. However, you could look at Monitor.Wait.
If you can have an async method, you can do something like to pause the function at a certain location. Once pause is set false it will continue executing the rest of the code in the method. Since this is an async method and delay is async too UI execution wouldn't be affected.
* Please note that asyn is supported only in .net 4.5 and higher.
bool pause = true;
void async foo()
{
//some code
while (pause)
{
await Task.Delay(100);
}
//some code
}

In C#, wait on the mainthread while continuing to process UI updates? (.NET 2.0 CF)

I want to otherwise block code execution on the main thread while still allowing UI changes to be displayed.
I tried to come up with a simplified example version of what I'm trying to do; and this is the best I could come up with. Obviously it doesn't demonstrate the behavior I'm wanting or I wouldn't be posting the question. I just hope it gives some code context to back my poor explanation of the problem I'm hoping to solve.
Within a button click handler on a form I have this:
private void button2_Click(object sender, EventArgs e)
{
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
new Thread(delegate()
{
// do something that takes a while.
Thread.Sleep(1000);
// Update UI w/BeginInvoke
this.BeginInvoke(new ThreadStart(
delegate() {
this.Text = "Working... 1";
this.Refresh();
Thread.Sleep(1000); // gimme a chance to see the new text
}));
// do something else that takes a while.
Thread.Sleep(1000);
// Update UI w/Invoke
this.Invoke(new ThreadStart(
delegate() {
this.Text = "Working... 2";
this.Refresh();
Thread.Sleep(1000); // gimme a chance to see the new text
}));
// do something else that takes a while.
Thread.Sleep(1000);
autoResetEvent.Set();
}).Start();
// I want the UI to update during this 4 seconds, even though I'm
// blocking the mainthread
if (autoResetEvent.WaitOne(4000, false))
{
this.Text = "Event Signalled";
}
else
{
this.Text = "Event Wait Timeout";
}
Thread.Sleep(1000); // gimme a chance to see the new text
this.Refresh();
}
If I didn't set a timout on the WaitOne() the app would deadlock on the Invoke() call.
As to why I'd want to do this, I've been tasked with moving one subsystem of an app to do work in a background thread, but still have it block user's workflow (the main thread) only sometimes and for certain types of work related to that subsystem only.
You want to use the "BackgroundWorker" class, which will take most of this pain out of this for you.. but as mentioned before, you'll also want to structure it so that the main thread is updating the UI and the worker is doing the heavy lifting.
It is easyer then you might think.
Suggestion: when you need a thread to perform some occasional work, get it from the threadpool, so you will not need strange/error prone recycling code.
When you want something on another thread to update your UI, you just need a reference to the form and to call Form.Invoke passing the UI code you want the main thread to execute; it's a best pactice, in an event, to release the UI thread as soon as possible.
Ie:
private void button1_Click(object sender, EventArgs e)
{
// this is the UI thread
ThreadPool.QueueUserWorkItem(delegate(object state)
{
// this is the background thread
// get the job done
Thread.Sleep(5000);
int result = 2 + 2;
// next call is to the Invoke method of the form
this.Invoke(new Action<int>(delegate(int res)
{
// this is the UI thread
// update it!
label1.Text = res.ToString();
}), result);
});
}
Hope this helps you:)
EDIT: I am sorry, I didn't read the "blocking user workflow" part.
WindowsForms is not designed to do that, blocking the main thread is BAD (it handles the messages from the OS).
You don't have to block the user workflow via freezing a form (which would then be considered "Not Responding" by windows), the way to block user workflow is by disabling any control you want (with the Invoke method above if from another thread), even the entire form!!
Common activities which 'block' the main thread are things like opening messages boxes or modal dialog. The main code appears to block at the MessageBox or ShowDialog call.
The way those items work (and MessageBox is just a specialized modal dialog) is that they contain their own message pump while they're blocking.
Although it's a nasty hack, you can do something like this in your app by looping calling Application.DoEvents() to keep the user messages pumping while you're waiting for your other task to complete. You need to be careful because all sorts of nasty things might lead from pumping messages like this - for example someone close the form or reenter your current message handler - the modal dialogs avoid this by effectively disabling input from the form which launches them.
I did mean to say that BackgroundWorker is a better solution, if you can make it fit. I sometimes combine it with a modal 'progress dialog' to give me the background thread / message pumping and the blocking of the UI thread.
Edit - to expand on the last bit:
One approach I've used is to have a 'progress form' class, which takes a BackgroundWorker object as a constructor parameter, and contains handlers for the progress and completion events of the background worker which gets passed to it.
The form which wants the work done creates the background worker and hooks up the 'work' event (can't remember what it's called right now), and then creates a progress dialog to which it passes the background worker. It then modally shows the progress dialog, which means it will wait (but pumping messages) until the progress dialog closes.
The progress form is responsible for starting the BackgroundWorker from its OnLoad override, and closes itself when it sees the BackgroundWorker complete. Obviously you can add message text, progress bars, cancel buttons, whatever to the progress form.
structure your app so that the main thread only performs UI updates, and all other work is done on secondary threads via a work queue; then add a waiting-for-godot flag to your main thread and use it to guard the method that adds items to the work queue
out of curiosity: why do you want to do this?
You should probably restructure your code as others have suggested, but depending on the behavior you're looking for, you might also want to have a look at using a Thread.Join on your background worker thread. Join actually allows the calling thread to process COM and SendMessage events while it waits for the other thread to finish. This seems like it could be dangerous in come cases, but I've actually had a couple scenarios where it was the only way to wait for another thread to finish cleanly.
Thread..::.Join Method
Blocks the calling thread until a
thread terminates, while continuing to
perform standard COM and SendMessage
pumping.
(from http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx)
I agree with the others that are suggesting you use Background Worker. It does the heavy lifting and allows the UI to continue. You can use the Report Progress of Background Worker to initiate times where the Main Form can be set to be disabled while it performs the actions in the background and then re-enable once the 'certain instances' have completed processing.
Let me know if this helps!
JFV
If you could adjust your code so that you set a flag once a process has begun and then check that in the UI before you start an additional operation I think you'd have a much easier time coding this. I would create a delegate that could be called from the thread in the threadpool or user created thread to update on progress in the UI. Once the background process has been completed switch the flag and now normal UI operations can continue. The only caveat you need to be aware of is that when you update UI components you must do it on the thread they were created on, the main/UI thread. In order to accomplish this you can call the Invoke() method on any control that lives on that thread and pass it the delegate and parameters you need to call it.
Here's a link to a tutorial I wrote some time ago about how to use Control.Invoke():
http://xsdev.net/tutorials/pop3fetcher/
Just a code snippet: don't have much time sorry :)
private void StartMyDoSomethingThread() {
Thread d = new Thread(new ThreadStart(DoSomething));
d.Start();
}
private void DoSomething() {
Thread.Sleep(1000);
ReportBack("I'm still working");
Thread.Sleep(1000);
ReportBack("I'm done");
}
private void ReportBack(string p) {
if (this.InvokeRequired) {
this.Invoke(new Action<string>(ReportBack), new object[] { p });
return;
}
this.Text = p;
}
It is best to dispatch the work but if you must, maybe something like this. Just call this method to wait for the signal rather than calling the waitone.
private static TimeSpan InfiniteTimeout = TimeSpan.FromMilliseconds(-1);
private const Int32 MAX_WAIT = 100;
public static bool Wait(WaitHandle handle, TimeSpan timeout)
{
Int32 expireTicks;
bool signaled;
Int32 waitTime;
bool exitLoop;
// guard the inputs
if (handle == null) {
throw new ArgumentNullException("handle");
}
else if ((handle.SafeWaitHandle.IsClosed)) {
throw new ArgumentException("closed wait handle", "handle");
}
else if ((handle.SafeWaitHandle.IsInvalid)) {
throw new ArgumentException("invalid wait handle", "handle");
}
else if ((timeout < InfiniteTimeout)) {
throw new ArgumentException("invalid timeout <-1", "timeout");
}
// wait for the signal
expireTicks = (int)Environment.TickCount + timeout.TotalMilliseconds;
do {
if (timeout.Equals(InfiniteTimeout)) {
waitTime = MAX_WAIT;
}
else {
waitTime = (expireTicks - Environment.TickCount);
if (waitTime <= 0) {
exitLoop = true;
waitTime = 0;
}
else if (waitTime > MAX_WAIT) {
waitTime = MAX_WAIT;
}
}
if ((handle.SafeWaitHandle.IsClosed)) {
exitLoop = true;
}
else if (handle.WaitOne(waitTime, false)) {
exitLoop = true;
signaled = true;
}
else {
if (Application.MessageLoop) {
Application.DoEvents();
}
else {
Thread.Sleep(1);
}
}
}
while (!exitLoop);
return signaled;
}
I went with something I haven't seen posted yet which is to use MessageQueues.
The MainThread blocks while waiting for the next message on a queue.
The background thread posts different types of messages to the MessageQueue.
Some of the message types signal the MainThread to update UI elements.
Of course, there is a message to tell the MainThread to stop blocking and waiting for messages.
Seems over the top considering the windows message loop already exists somewhere, but it works.

Categories

Resources