Do work in separate thread while maintaining UI responsiveness
5 replies, posted
I've got an app here and i'm trying to do some stuff in a separate thread so I can keep my UI snappy. The only problem is that I need it to also wait for the thread to finish before it continues along because right after the thread I have some variable checks, if I leave it as is, the program continues after spinning off the new thread and the checks fail and/or everything breaks. I thought about just putting everything that happens after clicking a button(thats what kicks off the new thread) into a single thread, but then I have the issue of changing UI controls from a separate thread which still breaks shit and with as much as i'm changing, it just wouldn't work to make a bunch of ugly delegates and shit. Does anyone have any ideas? I'm open to alternative solutions.
Oh, the reason i'm having to use another thread is i'm making a call out to a server and of course waiting for it takes "ages".
[QUOTE=Reason_Man;16442280]I've got an app here and i'm trying to do some stuff in a separate thread so I can keep my UI snappy. The only problem is that I need it to also wait for the thread to finish before it continues along because right after the thread I have some variable checks, if I leave it as is, the program continues after spinning off the new thread and the checks fail and/or everything breaks. I thought about just putting everything that happens after clicking a button(thats what kicks off the new thread) into a single thread, but then I have the issue of changing UI controls from a separate thread which still breaks shit and with as much as i'm changing, it just wouldn't work to make a bunch of ugly delegates and shit. Does anyone have any ideas? I'm open to alternative solutions.
Oh, the reason i'm having to use another thread is i'm making a call out to a server and of course waiting for it takes "ages".[/QUOTE]
Calling Invoke on controls is the only proper way to execute UI logic on another thread, but since .NET 3.5+, calling Invoke has become a lot easier.
The "old fashioned" Invoke method requires creating a delegate type and then a full function or anonymous delegate, but using Lambda expressions and an extension method, it can be alot easier.
[code]
public static class InvokeExtension
{
public static object Invoke( this Control ctrl, Action action )
{
return ctrl.Invoke( action );
}
}
// and the invocation:
private void button1_Click( object sender, EventArgs e )
{
Thread thread = new Thread( new ThreadStart( doInvoke ) );
thread.Start();
}
void doInvoke()
{
// much neater
label1.Invoke( () => label1.Text = "Label text" );
}
[/code]
Of course, if you are leaning more towards the other method, you could always poll a volatile boolean ready flag to see if logic should continue.
[code]
volatile bool readyToContinue = false;
private void button1_Click( object sender, EventArgs e )
{
Thread thread = new Thread( new ThreadStart( logicThread ) );
thread.Start();
while ( !readyToContinue )
{
Application.DoEvents();
// sleep to avoid heavy CPU usage, but keep the UI flowing
Thread.Sleep( 10 );
}
}
void logicThread()
{
// do some logic
readyToContinue = true;
}
[/code]
Ideally, you'd want to remove the Sleep call and do DateTime checks so that it doesn't rely heavily on scheduling.
Ideally i'd like to avoid having to update the UI from the second thread, and only have the actual work going on in it, otherwise i'd have way to many calls to Invoke and anonymous delegates and my code would become unreadable and unmanageable pretty fast.
The second option seems like it's the answer i'm after. I didn't know about the "volatile" keyword. I'm still pretty new to threading, can you explain why and how i'd use DateTime?
volatile makes it so when you access the var, you read the memory every time.
This is required since another thread is going to be changing that variable. You can't cache it.
[QUOTE=Reason_Man;16443584]I'm still pretty new to threading, can you explain why and how i'd use DateTime?[/QUOTE]
You'd use DateTime to pause execution in the loop for 10ms intervals (or whatever length you want), instead of relying on Sleep to do it for you.
But now that I think about it, it would still require a Sleep so that it wouldn't swamp CPU usage. I guess I'm just too used to game programming that I like to rely on intervals more than Sleep. :buddy:
So yeah, I'd stick with Sleep for your design.
There are alternatives such as [url=http://msdn.microsoft.com/en-us/library/system.threading.monitor.wait.aspx]Monitor.Wait[/url] and [url=http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse.aspx]Monitor.Pulse[/url], but these are generally used to pause and wake threads when they're both dependent on each other, which doesn't seem to be the case.
Sleep itself is generally a very poorly designed function, which tells the host OS that you want to relinquish control of the thread for however many milliseconds [i]at least[/i]. It's entirely possible that the OS could give control back much later, or even never based on the priority of other threads. This generally doesn't apply to your situation, but it's something you should be careful of.
I see, thanks.
My whole thing is i'm trying to emulate the process that the moveuser utility takes(migrate a local profile to a domain) without having to rely on the tool itself. Part of that process is hitting the domain to see if a user exists and setting permissions on a users profile directory both of which can take a long time, or no time at all. Obviously I want to keep my UI responding to input and updating notification controls along the way. Looking over my code I was able to cut the directory permission part down to only apply permissions on one directory and then just setting it to force inheritance on child objects. So now the only thread will be waiting on the domain to respond.
Sorry, you need to Log In to post a reply to this thread.