backgroundworker thread

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

If I create a backgroundworker thread within a windows forms application.
What happens if somone closes the windows form while the background worker
thread is running. Is their a way to change the behavior?
 
Did you try it?

You could put a check in the Form_Closing event for the form, and if the
background worker is still running, cancel the form_closing event.

Robin S.
 
Hi Chuck,

Based on my test, when we closed the main form while using BackgroundWorker
is still running, the entire application/process will terminate without
leaving BackgroundWorker thread alive. My test BackgroundWorker uses the
code below to keep the BackgroundWorker thread alive:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000000);
}

Further reseach shows that once the main Form thread is closed, it is
calling ExitProcess win32 API to terminate the entire process, so the
BackgroundWorker thread will be killed without any awareness. To prove
this, I used windbg to attach a test winform application and set a
breakpoint on KERNEL32!ExitProcess. After I closed the main form, the
windbg breaks on the breakpoint with the main thread stack trace below:

ChildEBP RetAddr
0013fd38 79f96d9b KERNEL32!ExitProcess
0013ff60 79f96dc7 mscorwks!SafeExitProcess+0x11a
0013ff6c 79f05fa4 mscorwks!HandleExitProcessHelper+0x25
0013ffb0 79011b5f mscorwks!_CorExeMain+0x8c
0013ffc0 77e523e5 mscoree!_CorExeMain+0x2c
0013fff0 00000000 KERNEL32!BaseProcessStart+0x23

At this time, I loaded sos.dll and view the live CLR threads:

0:000> .load sos
0:000> !threads
ThreadCount: 4
UnstartedThread: 0
BackgroundThread: 4
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count
APT Exception
0 1 92c 00191e00 6220 Enabled 014e3520:014e3fe8 0015ccb0 0
STA
2 2 14ec 0019bfa8 b220 Enabled 014e415c:014e5fe8 0015ccb0 0
MTA (Finalizer)
5 3 6a0 001e3458 1803220 Enabled 014cff00:014d0798 0015ccb0 0
MTA (Threadpool Worker)
6 4 17c4 001f2fb8 220 Enabled 00000000:00000000 0015ccb0 0
Ukn

BackgroundWorker thread is actually Threadpool Worker, so it may be thread
"5" in the above list. Dump it stack may confirm my statement:

0:000> ~5e!clrstack
OS Thread Id: 0x7dc (5)
ESP EIP
0490f43c 7c82ed54 [HelperMethodFrame: 0490f43c]
System.Threading.Thread.SleepInternal(Int32)
0490f490 793d80f5 System.Threading.Thread.Sleep(Int32)
0490f494 013703d3
BackgroundThreadTest.Form1.backgroundWorker1_DoWork(System.Object,
System.ComponentModel.DoWorkEventArgs)
0490f4a4 7a4d6026
System.ComponentModel.BackgroundWorker.OnDoWork(System.ComponentModel.DoWork
EventArgs)
0490f4b8 7a4d65ff
System.ComponentModel.BackgroundWorker.WorkerThreadStart(System.Object)
0490f8e8 79e88f63 [HelperMethodFrame_PROTECTOBJ: 0490f8e8]
System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(In
tPtr, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)
0490fa2c 794be820
System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(Sys
tem.RuntimeMethodHandle, System.Object[], System.Object, Int32, Boolean,
System.Object[] ByRef)
0490fa4c 794be2a3
System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(Syste
m.Runtime.Remoting.Messaging.IMessage,
System.Runtime.Remoting.Messaging.IMessageSink)
0490fab8 794b4949
System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Syst
em.Object)
0490fac8 793d912f
System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(System.Object)
0490fad0 793683dd
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
System.Threading.ContextCallback, System.Object)
0490fae8 793d9218
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(System.Object)
0490fc78 79e88f63 [GCFrame: 0490fc78]

Yes, at the time of ExitProcess API calling, the BackgroundWorker thread is
still alive. So it is really killed by ExitProcess API calling of main
thread.

Hope it helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Thanks,
I guess their is no way to change it to a foreground thread.


"Jeffrey Tan[MSFT]" said:
Hi Chuck,

Based on my test, when we closed the main form while using BackgroundWorker
is still running, the entire application/process will terminate without
leaving BackgroundWorker thread alive. My test BackgroundWorker uses the
code below to keep the BackgroundWorker thread alive:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000000);
}

Further reseach shows that once the main Form thread is closed, it is
calling ExitProcess win32 API to terminate the entire process, so the
BackgroundWorker thread will be killed without any awareness. To prove
this, I used windbg to attach a test winform application and set a
breakpoint on KERNEL32!ExitProcess. After I closed the main form, the
windbg breaks on the breakpoint with the main thread stack trace below:

ChildEBP RetAddr
0013fd38 79f96d9b KERNEL32!ExitProcess
0013ff60 79f96dc7 mscorwks!SafeExitProcess+0x11a
0013ff6c 79f05fa4 mscorwks!HandleExitProcessHelper+0x25
0013ffb0 79011b5f mscorwks!_CorExeMain+0x8c
0013ffc0 77e523e5 mscoree!_CorExeMain+0x2c
0013fff0 00000000 KERNEL32!BaseProcessStart+0x23

At this time, I loaded sos.dll and view the live CLR threads:

0:000> .load sos
0:000> !threads
ThreadCount: 4
UnstartedThread: 0
BackgroundThread: 4
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count
APT Exception
0 1 92c 00191e00 6220 Enabled 014e3520:014e3fe8 0015ccb0 0
STA
2 2 14ec 0019bfa8 b220 Enabled 014e415c:014e5fe8 0015ccb0 0
MTA (Finalizer)
5 3 6a0 001e3458 1803220 Enabled 014cff00:014d0798 0015ccb0 0
MTA (Threadpool Worker)
6 4 17c4 001f2fb8 220 Enabled 00000000:00000000 0015ccb0 0
Ukn

BackgroundWorker thread is actually Threadpool Worker, so it may be thread
"5" in the above list. Dump it stack may confirm my statement:

0:000> ~5e!clrstack
OS Thread Id: 0x7dc (5)
ESP EIP
0490f43c 7c82ed54 [HelperMethodFrame: 0490f43c]
System.Threading.Thread.SleepInternal(Int32)
0490f490 793d80f5 System.Threading.Thread.Sleep(Int32)
0490f494 013703d3
BackgroundThreadTest.Form1.backgroundWorker1_DoWork(System.Object,
System.ComponentModel.DoWorkEventArgs)
0490f4a4 7a4d6026
System.ComponentModel.BackgroundWorker.OnDoWork(System.ComponentModel.DoWork
EventArgs)
0490f4b8 7a4d65ff
System.ComponentModel.BackgroundWorker.WorkerThreadStart(System.Object)
0490f8e8 79e88f63 [HelperMethodFrame_PROTECTOBJ: 0490f8e8]
System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(In
tPtr, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)
0490fa2c 794be820
System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(Sys
tem.RuntimeMethodHandle, System.Object[], System.Object, Int32, Boolean,
System.Object[] ByRef)
0490fa4c 794be2a3
System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(Syste
m.Runtime.Remoting.Messaging.IMessage,
System.Runtime.Remoting.Messaging.IMessageSink)
0490fab8 794b4949
System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Syst
em.Object)
0490fac8 793d912f
System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(System.Object)
0490fad0 793683dd
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
System.Threading.ContextCallback, System.Object)
0490fae8 793d9218
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(System.Object)
0490fc78 79e88f63 [GCFrame: 0490fc78]

Yes, at the time of ExitProcess API calling, the BackgroundWorker thread is
still alive. So it is really killed by ExitProcess API calling of main
thread.

Hope it helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
I guess their is no way to make it a foreground thread?

Also is their a good way to have WaitOne functionality?
I coud use polling (kludge):
while (backgroundWorker1.IsBusy)
System.Threading.Thread.Sleep(10, 000); //sleep 10 seconds

I saw this, but don't quite follow it:

http://www.msnewsgroups.net/group/microsoft.public.dotnet.languages.csharp/topic17951.aspx

I write some windows forms app that if a parameter is passed in they have no
UI.
If no parameter, then you get the UI. These apps are for moving data around
at midnight etc. In the UI mode you can set/change setup parameters and
watch the data move. In the command line mode it just runs without the UI.

So the data moving class was designed for use with the Backgroundworker
style so it has lots of callbacks in it. In the console mode you don't
want the call backs, but you need to wait until the data move completes
because it's a background thread.



"Jeffrey Tan[MSFT]" said:
Hi Chuck,

Based on my test, when we closed the main form while using BackgroundWorker
is still running, the entire application/process will terminate without
leaving BackgroundWorker thread alive. My test BackgroundWorker uses the
code below to keep the BackgroundWorker thread alive:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000000);
}

Further reseach shows that once the main Form thread is closed, it is
calling ExitProcess win32 API to terminate the entire process, so the
BackgroundWorker thread will be killed without any awareness. To prove
this, I used windbg to attach a test winform application and set a
breakpoint on KERNEL32!ExitProcess. After I closed the main form, the
windbg breaks on the breakpoint with the main thread stack trace below:

ChildEBP RetAddr
0013fd38 79f96d9b KERNEL32!ExitProcess
0013ff60 79f96dc7 mscorwks!SafeExitProcess+0x11a
0013ff6c 79f05fa4 mscorwks!HandleExitProcessHelper+0x25
0013ffb0 79011b5f mscorwks!_CorExeMain+0x8c
0013ffc0 77e523e5 mscoree!_CorExeMain+0x2c
0013fff0 00000000 KERNEL32!BaseProcessStart+0x23

At this time, I loaded sos.dll and view the live CLR threads:

0:000> .load sos
0:000> !threads
ThreadCount: 4
UnstartedThread: 0
BackgroundThread: 4
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count
APT Exception
0 1 92c 00191e00 6220 Enabled 014e3520:014e3fe8 0015ccb0 0
STA
2 2 14ec 0019bfa8 b220 Enabled 014e415c:014e5fe8 0015ccb0 0
MTA (Finalizer)
5 3 6a0 001e3458 1803220 Enabled 014cff00:014d0798 0015ccb0 0
MTA (Threadpool Worker)
6 4 17c4 001f2fb8 220 Enabled 00000000:00000000 0015ccb0 0
Ukn

BackgroundWorker thread is actually Threadpool Worker, so it may be thread
"5" in the above list. Dump it stack may confirm my statement:

0:000> ~5e!clrstack
OS Thread Id: 0x7dc (5)
ESP EIP
0490f43c 7c82ed54 [HelperMethodFrame: 0490f43c]
System.Threading.Thread.SleepInternal(Int32)
0490f490 793d80f5 System.Threading.Thread.Sleep(Int32)
0490f494 013703d3
BackgroundThreadTest.Form1.backgroundWorker1_DoWork(System.Object,
System.ComponentModel.DoWorkEventArgs)
0490f4a4 7a4d6026
System.ComponentModel.BackgroundWorker.OnDoWork(System.ComponentModel.DoWork
EventArgs)
0490f4b8 7a4d65ff
System.ComponentModel.BackgroundWorker.WorkerThreadStart(System.Object)
0490f8e8 79e88f63 [HelperMethodFrame_PROTECTOBJ: 0490f8e8]
System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(In
tPtr, System.Object[], System.Object, Int32, Boolean, System.Object[] ByRef)
0490fa2c 794be820
System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(Sys
tem.RuntimeMethodHandle, System.Object[], System.Object, Int32, Boolean,
System.Object[] ByRef)
0490fa4c 794be2a3
System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(Syste
m.Runtime.Remoting.Messaging.IMessage,
System.Runtime.Remoting.Messaging.IMessageSink)
0490fab8 794b4949
System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Syst
em.Object)
0490fac8 793d912f
System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(System.Object)
0490fad0 793683dd
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
System.Threading.ContextCallback, System.Object)
0490fae8 793d9218
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(System.Object)
0490fc78 79e88f63 [GCFrame: 0490fc78]

Yes, at the time of ExitProcess API calling, the BackgroundWorker thread is
still alive. So it is really killed by ExitProcess API calling of main
thread.

Hope it helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Chuck,

Sorry for the late response, I am out of office yesterday.

Oh, yes, if your requirement is how to prevent the application from closing
before the background task is done, you may stop the main form from closing
in FormClosing event. The thread you found use a ManualResetEvent to do the
interthread synchronization.

Another choice is setting FormClosingEventArgs.Cancel to true in
Form1_FormClosing event(which cancels the form closing), then you may pop
up a dialog to the end user to notify them the background task is still in
process. This choice may be better than the ManualResetEvent one because
ManualResetEvent.WaitOne() calling in FormClosing event will hang the UI
thread of your winform application, which makes the use confused. If the
background task will cost long time, the hang may make the users think
there is something wrong in the application, so they may use task manager
to kill the winform application.

Anyway, if you have anything unclear, please feel free to tell me, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
thanks Jeffrey,

When the app runs in the command line mode I went with the
ManualResetEvent.WaitOne()

In the Windows forms mode I put in the backgroundWorker1.IsBusy
 
Hi Chuck,

Oh, thanks for your sharing! Yes, it seems that there is no need to use
another ManualResetEvent to check whether backgroundworker is running or
not, BackgroundWorker.IsBusy is an easier approach. :-)

If you have any further help or have any concern, please feel free to tell
me, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Back
Top