Thread and Not Responding
-
Thanks for the tip. If after i create the thread t and then do t.Join() the application don't stay "Not Responding" but it stays stopped until the thread t stopps. I think that the application stay's in "Not Responding" because in ApplicationTick1() i refer a recursive method. This method takes a while to do it's job and in that while the application stays "Not Responding". Here is a sample of the code in ApplicationTick1: // preenche a arvore MyDelegate d = new MyDelegate(LDAPLibrary.Class1.FillTreeView); this.Invoke(d,new object[] {conn,tv.Nodes,p2,true}); :((
That won't start a new thread.
Control.Invoke
actually executes the method on the thread on which the control was created. That's useful when you're doing something in a different thread and need to update the UI. As I said in my reply, you must always update the UI on the thread on which the control was created. That's why theControl
class implementsISynchronizeInvoke
. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog] -
Agreed, there are cases where you really need to use multi-threaded behavior and the example is a perfect example (begin/end process pipelines are classic MT fodder). Without more information however it sounds like the described problem can be fixed simply by avoiding MT all together. Sometimes the vague nature of the questions makes me suspicious which is why I asked the question. :-) If they can come up with the answer on why their app relies on MT behavior that requires going against MT behavior then we can actually go forward and get a better solution than vaguely throwing code around.
And I completely agree with you. I added a response to yours mainly for the original poster's benefit, since he/she might have a valid reason that falls under the scenario I mentioned. Turns out, though, that he/she is using
Control.Invoke
, apparently thinking that it will invoke the method on a different thread. Further proof that reading documentation is always beneficial. :) This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog] -
There's a couple ways of doing that. You can use
Thread.Join
in your main application thread. You would do something like this:Thread t = new Thread(new ThreadStart(SomeMethod));
t.Start();
// ...
t.Join()Now your main application thread (or in whichever thread you called
Join
will block until the thread terminates. Another way is through asynchronous processing and gives you added functionality, like callbacks. Many objects define asynchronous methods already (theBegin*
andEnd*
method pairs), but you execute any method (including property getters and setters, which are just methods) asynchronously like so:using System;
using System.Threading;
delegate void VoidCallback();
class Test
{
static void Main()
{
Test t = new Test();
VoidCallback callback = new VoidCallback(t.DoSomething);
IAsyncResult result = callback.BeginInvoke(null, null);
Thread.Sleep(1000);
Console.WriteLine("Still in Main() on main thread");
callback.EndInvoke(result);
Console.WriteLine("Done");
}
void DoSomething()
{
Console.WriteLine("Waiting for 3 seconds in new thread...");
Thread.Sleep(3000);
}
}While this is possible, however, an application should never appear hung (which is what you're doing). If you don't want the user to be able to interact with the application while still allowing the control thread (the thread on which the controls were created) to paint the controls (so the application doesn't appear hung), then simply set the wait cursor by doing
Cursor.Current = Cursors.WaitCursor;
. You can do this for a particular control (including the form, which extendsControl
) by settingControl.Cursor
or for the entire application by usingCursor.Current
. Be sure to restore the original cursor, however, or the user won't be able to interact (i.e., give intput) with your application. For example:Cursor orig = Cursor.Current;
try
{
Cursor.Current = Cursors.WaitCursor;
// Do stuff...
}
finall
{
Cursor.Current = orig;
}This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [
When I set Cursor.Current to the WaitCursor then start a thread to do a long process the Cursor doesn't remain as the WaitCursor it almost immediately changes back to the default cursor. My long process fires an event to say it has started and I handle that on the GUI thread (yes I am using invoke required and delegates) - this sets the Cursor.Current to the WaitCursor then when the long process has completed it fires another event which is handled on the GUI thread which sets the Cursor.Current to the default cursor. I would like the Cursor to remain as the WaitCursor until the long process has completed but no amount of jiggery pokery seems to enable me to do that - I have had to resort to disabling huge amounts of the GUI so the user can't mess up - a WaitCursor would be nice but it just isn't happening. I know the following is in VB but I haven't had much joy on the VB forum. The long running process fires off an event every 1000 records or so which is handled on the GU thread thus:
Private Delegate Sub xxxDelegate(ByVal sender As Object, ByVal e As xxxEventArgs) Private Sub xxx(ByVal sender As Object, ByVal e As xxxEventArgs) Handles LongProcess.xxx If button.InvokeRequired = False Then Console.WriteLine("A - " & Cursor.Current.ToString()) ... Else Console.WriteLine("B - " & Cursor.Current.ToString()) Dim del As New xxxDelegate(AddressOf xxx) Me.BeginInvoke(del, New Object() {sender, e}) End If End Sub
When run the following is written to the console: B - [Cursor: WaitCursor] A - [Cursor: Default] B - [Cursor: WaitCursor] A - [Cursor: Default] B - [Cursor: WaitCursor] A - [Cursor: Default] -
When I set Cursor.Current to the WaitCursor then start a thread to do a long process the Cursor doesn't remain as the WaitCursor it almost immediately changes back to the default cursor. My long process fires an event to say it has started and I handle that on the GUI thread (yes I am using invoke required and delegates) - this sets the Cursor.Current to the WaitCursor then when the long process has completed it fires another event which is handled on the GUI thread which sets the Cursor.Current to the default cursor. I would like the Cursor to remain as the WaitCursor until the long process has completed but no amount of jiggery pokery seems to enable me to do that - I have had to resort to disabling huge amounts of the GUI so the user can't mess up - a WaitCursor would be nice but it just isn't happening. I know the following is in VB but I haven't had much joy on the VB forum. The long running process fires off an event every 1000 records or so which is handled on the GU thread thus:
Private Delegate Sub xxxDelegate(ByVal sender As Object, ByVal e As xxxEventArgs) Private Sub xxx(ByVal sender As Object, ByVal e As xxxEventArgs) Handles LongProcess.xxx If button.InvokeRequired = False Then Console.WriteLine("A - " & Cursor.Current.ToString()) ... Else Console.WriteLine("B - " & Cursor.Current.ToString()) Dim del As New xxxDelegate(AddressOf xxx) Me.BeginInvoke(del, New Object() {sender, e}) End If End Sub
When run the following is written to the console: B - [Cursor: WaitCursor] A - [Cursor: Default] B - [Cursor: WaitCursor] A - [Cursor: Default] B - [Cursor: WaitCursor] A - [Cursor: Default]You wouldn't be calling
Application.DoEvents
would you? If not, you might run your application through a profiler (available from MSDN[^] even) to see if it's getting called automatically be something else. From the .NET Framework SDK for theCursor.Current
property:Note If you call Application.DoEvents before resetting the Current property back to the Cursors.Default cursor, the application will resume listening for mouse events and will resume displaying the appropriate Cursor for each control in the application.
This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog]
-
You wouldn't be calling
Application.DoEvents
would you? If not, you might run your application through a profiler (available from MSDN[^] even) to see if it's getting called automatically be something else. From the .NET Framework SDK for theCursor.Current
property:Note If you call Application.DoEvents before resetting the Current property back to the Cursors.Default cursor, the application will resume listening for mouse events and will resume displaying the appropriate Cursor for each control in the application.
This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog]
The app does call DoEvents but not anywhere touched by the long process - I usually call DoEvents after closing down a Dialog. I have run it under a profiler and DoEvents doesn't come into it. I am kicking off the long process using BeginInvoke - if that helps.
-
The app does call DoEvents but not anywhere touched by the long process - I usually call DoEvents after closing down a Dialog. I have run it under a profiler and DoEvents doesn't come into it. I am kicking off the long process using BeginInvoke - if that helps.
Where do you actually set
Cursor.Current
? Can you show me the rest of the code minus your application-specific implementation? This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog] -
Where do you actually set
Cursor.Current
? Can you show me the rest of the code minus your application-specific implementation? This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog]Hope this makes sense
Private Delegate Sub RunCrosstabDelegate(ByVal rowVar As String, ByVal colVar As String, ByVal thirdVar As String) Private Sub RunCrosstab() Dim crosstab As New RunCrosstabDelegate(AddressOf \_Counter.RunCrossTab) crosstab.BeginInvoke(LkCrossTab1.RowVariable, LkCrossTab1.ColVariable, LkCrossTab1.ThirdVariable, Nothing, Nothing) End Sub
Private Sub _Counter_CrossTabStart(ByVal sender As Object, ByVal e As EventArgs) Handles _Counter.CrossTabStart
If LkCrossTab1.InvokeRequired = False Then
Cursor.Current = System.Windows.Forms.Cursors.WaitCursor
Else
Dim del As New CrossTabStartDelegate(AddressOf _Counter_CrossTabStart)
Me.BeginInvoke(del, New Object() {sender, e})
End If
End SubPrivate Delegate Sub CrossTabFinishedDelegate(ByVal sender As Object, ByVal e As EventArgs) Private Sub \_Counter\_CrossTabFinished(ByVal sender As Object, ByVal e As EventArgs) Handles \_Counter.CrossTabFinished If LkCrossTab1.InvokeRequired = False Then Cursor.Current = System.Windows.Forms.Cursors.Default ' Else Dim del As New CrossTabFinishedDelegate(AddressOf \_Counter\_CrossTabFinished) Me.BeginInvoke(del, New Object() {sender, e}) End If End Sub
-
Hope this makes sense
Private Delegate Sub RunCrosstabDelegate(ByVal rowVar As String, ByVal colVar As String, ByVal thirdVar As String) Private Sub RunCrosstab() Dim crosstab As New RunCrosstabDelegate(AddressOf \_Counter.RunCrossTab) crosstab.BeginInvoke(LkCrossTab1.RowVariable, LkCrossTab1.ColVariable, LkCrossTab1.ThirdVariable, Nothing, Nothing) End Sub
Private Sub _Counter_CrossTabStart(ByVal sender As Object, ByVal e As EventArgs) Handles _Counter.CrossTabStart
If LkCrossTab1.InvokeRequired = False Then
Cursor.Current = System.Windows.Forms.Cursors.WaitCursor
Else
Dim del As New CrossTabStartDelegate(AddressOf _Counter_CrossTabStart)
Me.BeginInvoke(del, New Object() {sender, e})
End If
End SubPrivate Delegate Sub CrossTabFinishedDelegate(ByVal sender As Object, ByVal e As EventArgs) Private Sub \_Counter\_CrossTabFinished(ByVal sender As Object, ByVal e As EventArgs) Handles \_Counter.CrossTabFinished If LkCrossTab1.InvokeRequired = False Then Cursor.Current = System.Windows.Forms.Cursors.Default ' Else Dim del As New CrossTabFinishedDelegate(AddressOf \_Counter\_CrossTabFinished) Me.BeginInvoke(del, New Object() {sender, e}) End If End Sub
In your previous post you made it sounds like there was also an event that fired intermitently while the long process was running. Is that true? If so, do you set the wait cursor at all in that loop? When you profiled your application, no
Application.DoEvents
ran at all while processing the crosstab? From the code above I don't see a problem. It would seem another thread is either setting the cursor or dispatching queued messages (in the application pump). Since you're running asynchronously, this is entirely possible and most likely the case. Try running this synchronously and you should find that it works because the application (or dialog) message pump is run (whichApplication.DoEvents
forces). If that does work, I'm really not sure what to do to work around it, since this is expected behavior. One thing you could try is setting aControl
'sCursor
property instead of the application's. Hopefully that will "stick". This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog] -
In your previous post you made it sounds like there was also an event that fired intermitently while the long process was running. Is that true? If so, do you set the wait cursor at all in that loop? When you profiled your application, no
Application.DoEvents
ran at all while processing the crosstab? From the code above I don't see a problem. It would seem another thread is either setting the cursor or dispatching queued messages (in the application pump). Since you're running asynchronously, this is entirely possible and most likely the case. Try running this synchronously and you should find that it works because the application (or dialog) message pump is run (whichApplication.DoEvents
forces). If that does work, I'm really not sure what to do to work around it, since this is expected behavior. One thing you could try is setting aControl
'sCursor
property instead of the application's. Hopefully that will "stick". This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog]DoEvents isn't called at all during the processing. The WaitCursor just won't stick - I have tried setting the cursor on every single control to the WaitCursor - which kind of works although it doesn't stop mouseinput - the user can still click on things, drag stuff around, press buttons etc. So the WaitCursor doesn't seem to do much - is that what is supposed to happen? Is there a way to disable mouseinput without disabling every single control?
-
DoEvents isn't called at all during the processing. The WaitCursor just won't stick - I have tried setting the cursor on every single control to the WaitCursor - which kind of works although it doesn't stop mouseinput - the user can still click on things, drag stuff around, press buttons etc. So the WaitCursor doesn't seem to do much - is that what is supposed to happen? Is there a way to disable mouseinput without disabling every single control?
What are you using to profile the execution of your application? On other thing you might try is to override
OnCursorChanged
and set a breakpoint to see if anything else is setting it. Note that this event handler is not called if a native call changes it. You could setForm.KeyPreview
on the container form and disable keys effectively, but to disable mouse events for all child controls you'll need overrideWndProc
on the form and handle theWM_PARENTNOTIFY
(0x0210) message, where the low order (second half) of theMessage.LParam
is set toWM_LBUTTONDOWN
(0x0201) orWM_RBUTTONDOWN
(0x0204), and conditionally handle the message (allow it to be processed by callingbase.WndProc(ref Message)
). Your code must be fully trusted to overrideWndProc
. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles] [My Blog]