473,573 Members | 3,331 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Technique for Pausing Worker Thread

My first thought was to call

WorkerThread.Su spend

but the help cautions against this (for good reason) because the caller has
no control over where the thread actually stops, and it might have a lock
pending, for example.

I want to be able to stop a thread temporarily, and then optionally resume
it or stop it for good.

The code in the worker thread calls a recursive function, so passing some
flag down to the level at which the code is executing is quite messy. It
also calls methods on other objects that are defined locally, so a top-level
Pause method would not readily have a handle to one of the secondary
objects.

I should add that the worker thread code is contained in a worker thread
class, so what I am actually doing is something like

Dim wc as New WorkerClass

wc.StartThread ' starts worker thread and returns

' Do stuff
....

wc.Pause

It is this Pause that needs to stop the worker thread as soon as possible,
but at a sensible point.

Can anyone suggest a good technique for doing this? A pattern maybe?

A secondary question is: what should the thread do whilst it is paused?
Would it be reasonable for the thread to call Suspend on itself once it has
received the pause trigger? At least it would be able to execute the suspend
in a sensible place.

TIA

Charles
[I know ... you don't hear from me for ages and then suddenly the flood
gates open]
Nov 21 '05 #1
7 2673
Charles,
Is the worker thread going to pause itself or is another thread going to
pause the worker thread?

If another thread is going to pause the worker thread, my first choice would
be to use Thread.Suspend & Thread.Resume. However understanding the caveat
you identified.
It is this Pause that needs to stop the worker thread as soon as possible,
but at a sensible point. I would make WorkerClass.Pau se set an instance level variable, then at
opportune times the WorkerClass itself would call Thread.Suspend based on
this variable...

I would then make WorkerClass.UnP ause check to see if the Worker Thread
itself is suspended & call Thread.Resume.

Is the recursive function part of WorkerClass or part of the other objects?
If its part of WorkerClass it can easily check a instance level variable. As
you mention the other objects won't be able to check this variable.

An alternative to Thread.Suspend & Thread.Resume might be a
ManualResetEven t, where WorkerClass.Pau se Resets the event, and
WorkerClass.UnP ause sets the event, and at opportune times the WorkerClass
itself would WaitOne on the event. (thinking about it I might prefer the
ManualResetEven t over a different variable & Thread.Suspend &
Thread.Resume.. .).

A more advanced alternative might be using a shared field with
System.ThreadSt aticAttribute in your WorkerClass you might be able to give
the other objects an opportune time to suspend the thread, however the code
might get rather involved on getting it to work. As you would need to give
the WorkerClass the concept of "CurrentWorker" , where "CurrentWor ker" is a
shared property that returns the ThreadStatic variable, with the start
method (of the thread) the WorkerClass would need to save the instance in
the ThreadStatic variable...

Hope this helps
Jay
"Charles Law" <bl***@nowhere. com> wrote in message
news:OQ******** ******@TK2MSFTN GP09.phx.gbl... My first thought was to call

WorkerThread.Su spend

but the help cautions against this (for good reason) because the caller
has no control over where the thread actually stops, and it might have a
lock pending, for example.

I want to be able to stop a thread temporarily, and then optionally resume
it or stop it for good.

The code in the worker thread calls a recursive function, so passing some
flag down to the level at which the code is executing is quite messy. It
also calls methods on other objects that are defined locally, so a
top-level Pause method would not readily have a handle to one of the
secondary objects.

I should add that the worker thread code is contained in a worker thread
class, so what I am actually doing is something like

Dim wc as New WorkerClass

wc.StartThread ' starts worker thread and returns

' Do stuff
...

wc.Pause

It is this Pause that needs to stop the worker thread as soon as possible,
but at a sensible point.

Can anyone suggest a good technique for doing this? A pattern maybe?

A secondary question is: what should the thread do whilst it is paused?
Would it be reasonable for the thread to call Suspend on itself once it
has received the pause trigger? At least it would be able to execute the
suspend in a sensible place.

TIA

Charles
[I know ... you don't hear from me for ages and then suddenly the flood
gates open]

Nov 21 '05 #2
Jay

The worker thread is being paused by another thread.
Is the recursive function part of WorkerClass or part of the other
objects?
The recursive function is part of the other objects so, as you say, these
objects cannot readily check an instance variable.

Could you elaborate on the other two options? I am not quite sure how a
manual reset event would help where the recursive methods are concerned.
Would I still need to pass a reference into these recursive objects, and if
so, would that not also apply to the third option? Of course, if I am
passing in a reference, I can see how it would work, where a simple variable
would have to be passed at the point of pausing, rather than just at the
time of object creation.

Charles
"Jay B. Harlow [MVP - Outlook]" <Ja************ @msn.com> wrote in message
news:ew******** ********@TK2MSF TNGP09.phx.gbl. .. Charles,
Is the worker thread going to pause itself or is another thread going to
pause the worker thread?

If another thread is going to pause the worker thread, my first choice
would be to use Thread.Suspend & Thread.Resume. However understanding the
caveat you identified.
It is this Pause that needs to stop the worker thread as soon as
possible, but at a sensible point.

I would make WorkerClass.Pau se set an instance level variable, then at
opportune times the WorkerClass itself would call Thread.Suspend based on
this variable...

I would then make WorkerClass.UnP ause check to see if the Worker Thread
itself is suspended & call Thread.Resume.

Is the recursive function part of WorkerClass or part of the other
objects? If its part of WorkerClass it can easily check a instance level
variable. As you mention the other objects won't be able to check this
variable.

An alternative to Thread.Suspend & Thread.Resume might be a
ManualResetEven t, where WorkerClass.Pau se Resets the event, and
WorkerClass.UnP ause sets the event, and at opportune times the WorkerClass
itself would WaitOne on the event. (thinking about it I might prefer the
ManualResetEven t over a different variable & Thread.Suspend &
Thread.Resume.. .).

A more advanced alternative might be using a shared field with
System.ThreadSt aticAttribute in your WorkerClass you might be able to give
the other objects an opportune time to suspend the thread, however the
code might get rather involved on getting it to work. As you would need to
give the WorkerClass the concept of "CurrentWorker" , where "CurrentWor ker"
is a shared property that returns the ThreadStatic variable, with the
start method (of the thread) the WorkerClass would need to save the
instance in the ThreadStatic variable...

Hope this helps
Jay
"Charles Law" <bl***@nowhere. com> wrote in message
news:OQ******** ******@TK2MSFTN GP09.phx.gbl...
My first thought was to call

WorkerThread.Su spend

but the help cautions against this (for good reason) because the caller
has no control over where the thread actually stops, and it might have a
lock pending, for example.

I want to be able to stop a thread temporarily, and then optionally
resume it or stop it for good.

The code in the worker thread calls a recursive function, so passing some
flag down to the level at which the code is executing is quite messy. It
also calls methods on other objects that are defined locally, so a
top-level Pause method would not readily have a handle to one of the
secondary objects.

I should add that the worker thread code is contained in a worker thread
class, so what I am actually doing is something like

Dim wc as New WorkerClass

wc.StartThread ' starts worker thread and returns

' Do stuff
...

wc.Pause

It is this Pause that needs to stop the worker thread as soon as
possible, but at a sensible point.

Can anyone suggest a good technique for doing this? A pattern maybe?

A secondary question is: what should the thread do whilst it is paused?
Would it be reasonable for the thread to call Suspend on itself once it
has received the pause trigger? At least it would be able to execute the
suspend in a sensible place.

TIA

Charles
[I know ... you don't hear from me for ages and then suddenly the flood
gates open]


Nov 21 '05 #3
Charles,
Could you elaborate on the other two options? I am not quite sure how a
manual reset event would help where the recursive methods are concerned. The manual reset event does not help the recursive methods directly, it
helps them indirectly as the first thread Resets the event when the worker
thread needs to suspend itself. While the first thread Sets the event when
the worker thread is allowed to run.

The worker thread simply needs to periodically wait on the event. If the
event is Set, the worker thread will be allowed to continue to run, if the
event is Reset, the worker thread will be suspended. If the worker thread is
suspended, when the first thread sets the event, the worker thread would
then "wake up" and continue to run...
As you stated the other objects still need to call back into the
WorkerThread class to check the event. You could do this either with a
parameter or a shared "CurrentWor ker" property that relied on a ThreadStatic
field. It would really depend on what the other objects were doing if I
allowed them to have WorkerThread check the event, as this checking is
analogous to (very similar to) calling DoEvents in Windows Forms...
(technically its the inverse operation, however its analogous, as it gives
the code being called control over the threading)..
NOTE: The manual reset event does not have a concept of depth, its either on
or off...

Hope this helps
Jay
"Charles Law" <bl***@nowhere. com> wrote in message
news:u3******** ******@TK2MSFTN GP12.phx.gbl... Jay

The worker thread is being paused by another thread.
Is the recursive function part of WorkerClass or part of the other
objects?


The recursive function is part of the other objects so, as you say, these
objects cannot readily check an instance variable.

Could you elaborate on the other two options? I am not quite sure how a
manual reset event would help where the recursive methods are concerned.
Would I still need to pass a reference into these recursive objects, and
if so, would that not also apply to the third option? Of course, if I am
passing in a reference, I can see how it would work, where a simple
variable would have to be passed at the point of pausing, rather than just
at the time of object creation.

Charles
"Jay B. Harlow [MVP - Outlook]" <Ja************ @msn.com> wrote in message
news:ew******** ********@TK2MSF TNGP09.phx.gbl. ..
Charles,
Is the worker thread going to pause itself or is another thread going to
pause the worker thread?

If another thread is going to pause the worker thread, my first choice
would be to use Thread.Suspend & Thread.Resume. However understanding the
caveat you identified.
It is this Pause that needs to stop the worker thread as soon as
possible, but at a sensible point.

I would make WorkerClass.Pau se set an instance level variable, then at
opportune times the WorkerClass itself would call Thread.Suspend based on
this variable...

I would then make WorkerClass.UnP ause check to see if the Worker Thread
itself is suspended & call Thread.Resume.

Is the recursive function part of WorkerClass or part of the other
objects? If its part of WorkerClass it can easily check a instance level
variable. As you mention the other objects won't be able to check this
variable.

An alternative to Thread.Suspend & Thread.Resume might be a
ManualResetEven t, where WorkerClass.Pau se Resets the event, and
WorkerClass.UnP ause sets the event, and at opportune times the
WorkerClass itself would WaitOne on the event. (thinking about it I might
prefer the ManualResetEven t over a different variable & Thread.Suspend &
Thread.Resume.. .).

A more advanced alternative might be using a shared field with
System.ThreadSt aticAttribute in your WorkerClass you might be able to
give the other objects an opportune time to suspend the thread, however
the code might get rather involved on getting it to work. As you would
need to give the WorkerClass the concept of "CurrentWorker" , where
"CurrentWor ker" is a shared property that returns the ThreadStatic
variable, with the start method (of the thread) the WorkerClass would
need to save the instance in the ThreadStatic variable...

Hope this helps
Jay
"Charles Law" <bl***@nowhere. com> wrote in message
news:OQ******** ******@TK2MSFTN GP09.phx.gbl...
My first thought was to call

WorkerThread.Su spend

but the help cautions against this (for good reason) because the caller
has no control over where the thread actually stops, and it might have a
lock pending, for example.

I want to be able to stop a thread temporarily, and then optionally
resume it or stop it for good.

The code in the worker thread calls a recursive function, so passing
some flag down to the level at which the code is executing is quite
messy. It also calls methods on other objects that are defined locally,
so a top-level Pause method would not readily have a handle to one of
the secondary objects.

I should add that the worker thread code is contained in a worker thread
class, so what I am actually doing is something like

Dim wc as New WorkerClass

wc.StartThread ' starts worker thread and returns

' Do stuff
...

wc.Pause

It is this Pause that needs to stop the worker thread as soon as
possible, but at a sensible point.

Can anyone suggest a good technique for doing this? A pattern maybe?

A secondary question is: what should the thread do whilst it is paused?
Would it be reasonable for the thread to call Suspend on itself once it
has received the pause trigger? At least it would be able to execute the
suspend in a sensible place.

TIA

Charles
[I know ... you don't hear from me for ages and then suddenly the flood
gates open]



Nov 21 '05 #4
Ok. I think I'm with you now. So, in the scenario below
UI | Worker Object1 Object2
start
-----> -----> -----> Do
<----- ...
Loop
<---------|
-----> ...
pause
------>
What I am trying to show is that the UI kicks off the worker and gets
control back immediately. The worker passes control to Object1, which passes
control to Object2. Object2 loops for a bit, doing stuff, including making
recursive calls. Then, control passes back to Object1. Later, control passes
back to Object2 to do more stuff, and so on.

Then, the UI pauses the worker thread. The worker action is all taking place
down in Object2, and maybe a couple of recursions deep. Am I right to say
that when the worker passes control to Object1, it has to pass a
reference/handle to the reset event. Object1 must pass this to Object2. So
long as the recursion remains within Object2, no further parameter need be
passed, as the handle can be held in an object level variable. If the
recursion ventures into another object then that object must receive a
reference to the event.

Object2 must occasionally wait on the event, most logically within the loop.

When the pause occurs, the event is reset by the worker, and no further
action need be taken, as this will be seen wherever the thread waits on the
event, even in other objects.

Where does the ThreadStatic field come in? As I understand it, such a field
would still only be visible to the object in which it was created, so it
does not eliminate the need for passing a reference to the other objects in
the processing chain. Is there a way to prevent the need for passing a
reference around?

Charles
"Jay B. Harlow [MVP - Outlook]" <Ja************ @msn.com> wrote in message
news:uo******** ******@TK2MSFTN GP14.phx.gbl...
Charles,
Could you elaborate on the other two options? I am not quite sure how a
manual reset event would help where the recursive methods are concerned.

The manual reset event does not help the recursive methods directly, it
helps them indirectly as the first thread Resets the event when the worker
thread needs to suspend itself. While the first thread Sets the event when
the worker thread is allowed to run.

The worker thread simply needs to periodically wait on the event. If the
event is Set, the worker thread will be allowed to continue to run, if the
event is Reset, the worker thread will be suspended. If the worker thread
is suspended, when the first thread sets the event, the worker thread
would then "wake up" and continue to run...
As you stated the other objects still need to call back into the
WorkerThread class to check the event. You could do this either with a
parameter or a shared "CurrentWor ker" property that relied on a
ThreadStatic field. It would really depend on what the other objects were
doing if I allowed them to have WorkerThread check the event, as this
checking is analogous to (very similar to) calling DoEvents in Windows
Forms... (technically its the inverse operation, however its analogous, as
it gives the code being called control over the threading)..
NOTE: The manual reset event does not have a concept of depth, its either
on or off...

Hope this helps
Jay
"Charles Law" <bl***@nowhere. com> wrote in message
news:u3******** ******@TK2MSFTN GP12.phx.gbl...
Jay

The worker thread is being paused by another thread.
Is the recursive function part of WorkerClass or part of the other
objects?


The recursive function is part of the other objects so, as you say, these
objects cannot readily check an instance variable.

Could you elaborate on the other two options? I am not quite sure how a
manual reset event would help where the recursive methods are concerned.
Would I still need to pass a reference into these recursive objects, and
if so, would that not also apply to the third option? Of course, if I am
passing in a reference, I can see how it would work, where a simple
variable would have to be passed at the point of pausing, rather than
just at the time of object creation.

Charles
"Jay B. Harlow [MVP - Outlook]" <Ja************ @msn.com> wrote in message
news:ew******** ********@TK2MSF TNGP09.phx.gbl. ..
Charles,
Is the worker thread going to pause itself or is another thread going to
pause the worker thread?

If another thread is going to pause the worker thread, my first choice
would be to use Thread.Suspend & Thread.Resume. However understanding
the caveat you identified.

It is this Pause that needs to stop the worker thread as soon as
possible, but at a sensible point.
I would make WorkerClass.Pau se set an instance level variable, then at
opportune times the WorkerClass itself would call Thread.Suspend based
on this variable...

I would then make WorkerClass.UnP ause check to see if the Worker Thread
itself is suspended & call Thread.Resume.

Is the recursive function part of WorkerClass or part of the other
objects? If its part of WorkerClass it can easily check a instance level
variable. As you mention the other objects won't be able to check this
variable.

An alternative to Thread.Suspend & Thread.Resume might be a
ManualResetEven t, where WorkerClass.Pau se Resets the event, and
WorkerClass.UnP ause sets the event, and at opportune times the
WorkerClass itself would WaitOne on the event. (thinking about it I
might prefer the ManualResetEven t over a different variable &
Thread.Suspend & Thread.Resume.. .).

A more advanced alternative might be using a shared field with
System.ThreadSt aticAttribute in your WorkerClass you might be able to
give the other objects an opportune time to suspend the thread, however
the code might get rather involved on getting it to work. As you would
need to give the WorkerClass the concept of "CurrentWorker" , where
"CurrentWor ker" is a shared property that returns the ThreadStatic
variable, with the start method (of the thread) the WorkerClass would
need to save the instance in the ThreadStatic variable...

Hope this helps
Jay
"Charles Law" <bl***@nowhere. com> wrote in message
news:OQ******** ******@TK2MSFTN GP09.phx.gbl...
My first thought was to call

WorkerThread.Su spend

but the help cautions against this (for good reason) because the caller
has no control over where the thread actually stops, and it might have
a lock pending, for example.

I want to be able to stop a thread temporarily, and then optionally
resume it or stop it for good.

The code in the worker thread calls a recursive function, so passing
some flag down to the level at which the code is executing is quite
messy. It also calls methods on other objects that are defined locally,
so a top-level Pause method would not readily have a handle to one of
the secondary objects.

I should add that the worker thread code is contained in a worker
thread class, so what I am actually doing is something like

Dim wc as New WorkerClass

wc.StartThread ' starts worker thread and returns

' Do stuff
...

wc.Pause

It is this Pause that needs to stop the worker thread as soon as
possible, but at a sensible point.

Can anyone suggest a good technique for doing this? A pattern maybe?

A secondary question is: what should the thread do whilst it is paused?
Would it be reasonable for the thread to call Suspend on itself once it
has received the pause trigger? At least it would be able to execute
the suspend in a sensible place.

TIA

Charles
[I know ... you don't hear from me for ages and then suddenly the flood
gates open]



Nov 21 '05 #5
Charles,
The rules of encapsulation states, that you do not pass the Event itself to
object1 & object2, as the Event itself is an implementation detail of the
Worker class.

You could pass the instance of the Worker class to object1 & object2,
however it can be easier for object1 & object2 to simply call a shared
method of the Worker class. Either way object1 & object2 would be coupled to
Worker, whether I used a shared property or a parameter would depend on how
many routines & classes I needed to pass the parameter to. If object1 &
object2 "exists" only on a single thread I have been known to pass the
"Worker" class to the constructor of object1 & object2, then the any method
can gain access to the "current" "Worker" object...
If you call a shared method on the Worker class, the Worker class needs to
know the instance of the Worker class that is associated with the current
thread. You can use the Thread Static variable to associate the instance of
the Worker class with each thread, as the ThreadStatic variable causes the
shared member to be unique per thread... Alternatively you could use a
shared HashTable, where the Thread ID is the key & the Worker instance is
the value...
By encapsulating the Event within Worker you also gain more readable code,
your UI thread can call Worker.Suspend & Worker.Resume, while the Worker
thread itself would call Worker.CheckSus pend.
Here is a an example of a Worker class using a ManualResetEven t to control
suspending & resuming.

Public Class Worker

Public Delegate Sub Work()

Private ReadOnly m_work As Work
Private ReadOnly m_arg As Object
Private ReadOnly m_event As ManualResetEven t
Private ReadOnly m_thread As Thread

<ThreadStatic() > _
Private Shared m_current As Worker

Public Sub New(ByVal work As Work, ByVal arg As Object, ByVal name
As String)
m_work = work
m_arg = arg
m_event = New ManualResetEven t(True)
m_thread = New Thread(AddressO f Start)
m_thread.Name = name
m_thread.IsBack ground = True
m_thread.Start( )
End Sub

Private Sub Start()
m_current = Me
m_work.Invoke()
End Sub

Public Shared ReadOnly Property CurrentWorker() As Worker
Get
Return m_current
End Get
End Property

Public ReadOnly Property Arg() As Object
Get
Return m_arg
End Get
End Property

Public ReadOnly Property Name() As String
Get
Return m_thread.Name
End Get
End Property

Public Sub Suspend()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Sus pend should not be
called from the worker thread!")
End If
m_event.Reset()
End Sub

Public Sub [Resume]()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Res ume should not be
called from the worker thread!")
End If
m_event.Set()
End Sub

Public Sub WaitForTerminat ion()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Wai tForTermination
should not be called from the worker thread!")
End If
m_thread.Join()
End Sub

Public Sub CheckSuspend()
If Not Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Che ckSuspend should
only be called from the worker thread!")
End If
m_event.WaitOne ()
End Sub

End Class

To see how it works try something like:

Private Sub Work()
For index As Integer = 1 To 50
Worker.CurrentW orker.CheckSusp end()
Debug.WriteLine (index, Worker.CurrentW orker.Name)
Dim value As Double = DirectCast(Work er.CurrentWorke r.Arg,
Double)
Thread.Sleep(Ti meSpan.FromSeco nds(value))
Next
End Sub

Public Sub Main()
Dim worker1 As New Worker(AddressO f Work, 0.25, "worker1")
Dim worker2 As New Worker(AddressO f Work, 0.5, "worker2")
Dim worker3 As New Worker(AddressO f Work, 0.75, "worker3")

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker1.Suspend ()

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker2.Suspend ()

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker3.Suspend ()

Debug.WriteLine ("Pausing 1 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(1))

worker1.Resume( )
worker2.Resume( )
worker3.Resume( )

Debug.WriteLine ("Waiting for Termination", "Main")
worker1.WaitFor Termination()
worker2.WaitFor Termination()
worker3.WaitFor Termination()

End Sub

Hope this helps
Jay

"Charles Law" <bl***@nowhere. com> wrote in message
news:uh******** ********@tk2msf tngp13.phx.gbl. ..
Ok. I think I'm with you now. So, in the scenario below
UI | Worker Object1 Object2
start
-----> -----> -----> Do
<----- ...
Loop
<---------|
-----> ...
pause
------>
What I am trying to show is that the UI kicks off the worker and gets
control back immediately. The worker passes control to Object1, which
passes control to Object2. Object2 loops for a bit, doing stuff, including
making recursive calls. Then, control passes back to Object1. Later,
control passes back to Object2 to do more stuff, and so on.

Then, the UI pauses the worker thread. The worker action is all taking
place down in Object2, and maybe a couple of recursions deep. Am I right
to say that when the worker passes control to Object1, it has to pass a
reference/handle to the reset event. Object1 must pass this to Object2. So
long as the recursion remains within Object2, no further parameter need be
passed, as the handle can be held in an object level variable. If the
recursion ventures into another object then that object must receive a
reference to the event.

Object2 must occasionally wait on the event, most logically within the
loop.

When the pause occurs, the event is reset by the worker, and no further
action need be taken, as this will be seen wherever the thread waits on
the event, even in other objects.

Where does the ThreadStatic field come in? As I understand it, such a
field would still only be visible to the object in which it was created,
so it does not eliminate the need for passing a reference to the other
objects in the processing chain. Is there a way to prevent the need for
passing a reference around?

Charles

<<snip>>
Nov 21 '05 #6
An alternate Worker.Suspend implementation might be:

Public Sub Suspend()
m_event.Reset()
If Thread.CurrentT hread Is m_thread Then
m_event.WaitOne ()
End If
End Sub

Which allows the worker thread to suspend itself.

I would also consider implementing CurrentWorker as:

Public Shared ReadOnly Property CurrentWorker() As Worker
Get
If m_current Is Nothing Then
Throw New InvalidOperatio nException("Cur rentWorker
should only be called from a Worker thread!")
End If
Return m_current
End Get
End Property

To ensure that it is only called from Worker Threads (preventing
NullReferenceEx ceptions in non-worker threads!).

Hope this helps
Jay

"Jay B. Harlow [MVP - Outlook]" <Ja************ @msn.com> wrote in message
news:%2******** ********@TK2MSF TNGP14.phx.gbl. ..
Charles,
The rules of encapsulation states, that you do not pass the Event itself
to object1 & object2, as the Event itself is an implementation detail of
the Worker class.

You could pass the instance of the Worker class to object1 & object2,
however it can be easier for object1 & object2 to simply call a shared
method of the Worker class. Either way object1 & object2 would be coupled
to Worker, whether I used a shared property or a parameter would depend on
how many routines & classes I needed to pass the parameter to. If object1
& object2 "exists" only on a single thread I have been known to pass the
"Worker" class to the constructor of object1 & object2, then the any
method can gain access to the "current" "Worker" object...
If you call a shared method on the Worker class, the Worker class needs to
know the instance of the Worker class that is associated with the current
thread. You can use the Thread Static variable to associate the instance
of the Worker class with each thread, as the ThreadStatic variable causes
the shared member to be unique per thread... Alternatively you could use a
shared HashTable, where the Thread ID is the key & the Worker instance is
the value...
By encapsulating the Event within Worker you also gain more readable code,
your UI thread can call Worker.Suspend & Worker.Resume, while the Worker
thread itself would call Worker.CheckSus pend.
Here is a an example of a Worker class using a ManualResetEven t to control
suspending & resuming.

Public Class Worker

Public Delegate Sub Work()

Private ReadOnly m_work As Work
Private ReadOnly m_arg As Object
Private ReadOnly m_event As ManualResetEven t
Private ReadOnly m_thread As Thread

<ThreadStatic() > _
Private Shared m_current As Worker

Public Sub New(ByVal work As Work, ByVal arg As Object, ByVal name
As String)
m_work = work
m_arg = arg
m_event = New ManualResetEven t(True)
m_thread = New Thread(AddressO f Start)
m_thread.Name = name
m_thread.IsBack ground = True
m_thread.Start( )
End Sub

Private Sub Start()
m_current = Me
m_work.Invoke()
End Sub

Public Shared ReadOnly Property CurrentWorker() As Worker
Get
Return m_current
End Get
End Property

Public ReadOnly Property Arg() As Object
Get
Return m_arg
End Get
End Property

Public ReadOnly Property Name() As String
Get
Return m_thread.Name
End Get
End Property

Public Sub Suspend()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Sus pend should not be
called from the worker thread!")
End If
m_event.Reset()
End Sub

Public Sub [Resume]()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Res ume should not be
called from the worker thread!")
End If
m_event.Set()
End Sub

Public Sub WaitForTerminat ion()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Wai tForTermination
should not be called from the worker thread!")
End If
m_thread.Join()
End Sub

Public Sub CheckSuspend()
If Not Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Che ckSuspend should
only be called from the worker thread!")
End If
m_event.WaitOne ()
End Sub

End Class

To see how it works try something like:

Private Sub Work()
For index As Integer = 1 To 50
Worker.CurrentW orker.CheckSusp end()
Debug.WriteLine (index, Worker.CurrentW orker.Name)
Dim value As Double = DirectCast(Work er.CurrentWorke r.Arg,
Double)
Thread.Sleep(Ti meSpan.FromSeco nds(value))
Next
End Sub

Public Sub Main()
Dim worker1 As New Worker(AddressO f Work, 0.25, "worker1")
Dim worker2 As New Worker(AddressO f Work, 0.5, "worker2")
Dim worker3 As New Worker(AddressO f Work, 0.75, "worker3")

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker1.Suspend ()

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker2.Suspend ()

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker3.Suspend ()

Debug.WriteLine ("Pausing 1 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(1))

worker1.Resume( )
worker2.Resume( )
worker3.Resume( )

Debug.WriteLine ("Waiting for Termination", "Main")
worker1.WaitFor Termination()
worker2.WaitFor Termination()
worker3.WaitFor Termination()

End Sub

Hope this helps
Jay

"Charles Law" <bl***@nowhere. com> wrote in message
news:uh******** ********@tk2msf tngp13.phx.gbl. ..
Ok. I think I'm with you now. So, in the scenario below
UI | Worker Object1 Object2
start
-----> -----> -----> Do
<----- ...
Loop
<---------|
-----> ...
pause
------>
What I am trying to show is that the UI kicks off the worker and gets
control back immediately. The worker passes control to Object1, which
passes control to Object2. Object2 loops for a bit, doing stuff,
including making recursive calls. Then, control passes back to Object1.
Later, control passes back to Object2 to do more stuff, and so on.

Then, the UI pauses the worker thread. The worker action is all taking
place down in Object2, and maybe a couple of recursions deep. Am I right
to say that when the worker passes control to Object1, it has to pass a
reference/handle to the reset event. Object1 must pass this to Object2.
So long as the recursion remains within Object2, no further parameter
need be passed, as the handle can be held in an object level variable. If
the recursion ventures into another object then that object must receive
a reference to the event.

Object2 must occasionally wait on the event, most logically within the
loop.

When the pause occurs, the event is reset by the worker, and no further
action need be taken, as this will be seen wherever the thread waits on
the event, even in other objects.

Where does the ThreadStatic field come in? As I understand it, such a
field would still only be visible to the object in which it was created,
so it does not eliminate the need for passing a reference to the other
objects in the processing chain. Is there a way to prevent the need for
passing a reference around?

Charles

<<snip>>

Nov 21 '05 #7
Hi Jay

I have spent some time digesting this, and have now implemented something
along these lines in my project. It works just fine.

Thanks.

Charles
"Jay B. Harlow [MVP - Outlook]" <Ja************ @msn.com> wrote in message
news:%2******** ********@TK2MSF TNGP14.phx.gbl. ..
Charles,
The rules of encapsulation states, that you do not pass the Event itself
to object1 & object2, as the Event itself is an implementation detail of
the Worker class.

You could pass the instance of the Worker class to object1 & object2,
however it can be easier for object1 & object2 to simply call a shared
method of the Worker class. Either way object1 & object2 would be coupled
to Worker, whether I used a shared property or a parameter would depend on
how many routines & classes I needed to pass the parameter to. If object1
& object2 "exists" only on a single thread I have been known to pass the
"Worker" class to the constructor of object1 & object2, then the any
method can gain access to the "current" "Worker" object...
If you call a shared method on the Worker class, the Worker class needs to
know the instance of the Worker class that is associated with the current
thread. You can use the Thread Static variable to associate the instance
of the Worker class with each thread, as the ThreadStatic variable causes
the shared member to be unique per thread... Alternatively you could use a
shared HashTable, where the Thread ID is the key & the Worker instance is
the value...
By encapsulating the Event within Worker you also gain more readable code,
your UI thread can call Worker.Suspend & Worker.Resume, while the Worker
thread itself would call Worker.CheckSus pend.
Here is a an example of a Worker class using a ManualResetEven t to control
suspending & resuming.

Public Class Worker

Public Delegate Sub Work()

Private ReadOnly m_work As Work
Private ReadOnly m_arg As Object
Private ReadOnly m_event As ManualResetEven t
Private ReadOnly m_thread As Thread

<ThreadStatic() > _
Private Shared m_current As Worker

Public Sub New(ByVal work As Work, ByVal arg As Object, ByVal name
As String)
m_work = work
m_arg = arg
m_event = New ManualResetEven t(True)
m_thread = New Thread(AddressO f Start)
m_thread.Name = name
m_thread.IsBack ground = True
m_thread.Start( )
End Sub

Private Sub Start()
m_current = Me
m_work.Invoke()
End Sub

Public Shared ReadOnly Property CurrentWorker() As Worker
Get
Return m_current
End Get
End Property

Public ReadOnly Property Arg() As Object
Get
Return m_arg
End Get
End Property

Public ReadOnly Property Name() As String
Get
Return m_thread.Name
End Get
End Property

Public Sub Suspend()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Sus pend should not be
called from the worker thread!")
End If
m_event.Reset()
End Sub

Public Sub [Resume]()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Res ume should not be
called from the worker thread!")
End If
m_event.Set()
End Sub

Public Sub WaitForTerminat ion()
If Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Wai tForTermination
should not be called from the worker thread!")
End If
m_thread.Join()
End Sub

Public Sub CheckSuspend()
If Not Thread.CurrentT hread Is m_thread Then
Throw New InvalidOperatio nException("Che ckSuspend should
only be called from the worker thread!")
End If
m_event.WaitOne ()
End Sub

End Class

To see how it works try something like:

Private Sub Work()
For index As Integer = 1 To 50
Worker.CurrentW orker.CheckSusp end()
Debug.WriteLine (index, Worker.CurrentW orker.Name)
Dim value As Double = DirectCast(Work er.CurrentWorke r.Arg,
Double)
Thread.Sleep(Ti meSpan.FromSeco nds(value))
Next
End Sub

Public Sub Main()
Dim worker1 As New Worker(AddressO f Work, 0.25, "worker1")
Dim worker2 As New Worker(AddressO f Work, 0.5, "worker2")
Dim worker3 As New Worker(AddressO f Work, 0.75, "worker3")

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker1.Suspend ()

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker2.Suspend ()

Debug.WriteLine ("Pausing 5 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(5))
worker3.Suspend ()

Debug.WriteLine ("Pausing 1 seconds", "Main")
Thread.Sleep(Ti meSpan.FromSeco nds(1))

worker1.Resume( )
worker2.Resume( )
worker3.Resume( )

Debug.WriteLine ("Waiting for Termination", "Main")
worker1.WaitFor Termination()
worker2.WaitFor Termination()
worker3.WaitFor Termination()

End Sub

Hope this helps
Jay

"Charles Law" <bl***@nowhere. com> wrote in message
news:uh******** ********@tk2msf tngp13.phx.gbl. ..
Ok. I think I'm with you now. So, in the scenario below
UI | Worker Object1 Object2
start
-----> -----> -----> Do
<----- ...
Loop
<---------|
-----> ...
pause
------>
What I am trying to show is that the UI kicks off the worker and gets
control back immediately. The worker passes control to Object1, which
passes control to Object2. Object2 loops for a bit, doing stuff,
including making recursive calls. Then, control passes back to Object1.
Later, control passes back to Object2 to do more stuff, and so on.

Then, the UI pauses the worker thread. The worker action is all taking
place down in Object2, and maybe a couple of recursions deep. Am I right
to say that when the worker passes control to Object1, it has to pass a
reference/handle to the reset event. Object1 must pass this to Object2.
So long as the recursion remains within Object2, no further parameter
need be passed, as the handle can be held in an object level variable. If
the recursion ventures into another object then that object must receive
a reference to the event.

Object2 must occasionally wait on the event, most logically within the
loop.

When the pause occurs, the event is reset by the worker, and no further
action need be taken, as this will be seen wherever the thread waits on
the event, even in other objects.

Where does the ThreadStatic field come in? As I understand it, such a
field would still only be visible to the object in which it was created,
so it does not eliminate the need for passing a reference to the other
objects in the processing chain. Is there a way to prevent the need for
passing a reference around?

Charles

<<snip>>

Nov 21 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
2192
by: Coot | last post by:
I've been running many tests of the Asynchronous Delegate technique and I find that although BeginInvoke() does queue the method delegate onto a worker thread, it always does so on the _same_ thread. So if I call BeginInvoke() three times in a row, the method delegates are queued to the same thread and the second method doesn't begin until...
5
8096
by: Stephen Lamb | last post by:
I have a background worker thread which I start from a form's HandleCreated event that makes calls back to the form using Invoke. During shutdown the form is disposed and the background worker thread is aborted by the system. How is one to keep the background thread from calling form.Invoke after the form's window handle has been destroyed?...
1
1477
by: Doug Bright | last post by:
Hello all, I'm trying to build a .NET component the fires events from a worker thread, and I'm getting running into problems with the whole "controls must be modified only on the calling thread" issue. There were a couple of well known techniques for dealing with this through a COM interface, but, despite how easy it seems with .NET, I'm...
7
2113
by: Jeff Stewart | last post by:
I need a thread to run a subroutine which updates my main form's progress bar. I've properly marshaled all UI updates to the main UI thread, and after the main thread starts the worker thread, it waits for the worker thread to complete by means of a while t.isAlive, sleep(0) mechanism. But when my worker thread calls my UpdateProgressBar...
6
5980
by: Joe Jax | last post by:
I have an object that spawns a worker thread to process one of its methods. That method processes methods on a collection of other objects. During this processing, a user may request to cancel the entire operation. I could request abort on the worker thread, but that is a) potentially messy, and b) not guaranteed to take immediate effect...
5
3531
by: Soren S. Jorgensen | last post by:
Hi, In my app I've got a worker thread (background) doing some calculations based upon user input. A new worker thread might be invoked before the previous worker thread has ended, and I wan't only one worker thread running at any time (if a new worker thread start has been requested, any running worker thread results will be invalid). I'm...
14
6859
by: joey.powell | last post by:
I am using VS2005 for a windows forms application. I need to be able to use a worker thread function to offload some processing from the UI thread. The worker thread will need access to a datagridview on the form. I am using the following code to spawn the worker thread... Thread WorkerThread = new Thread(new ThreadStart(WT_MyFunction));...
0
2444
by: =?Utf-8?B?aGVyYmVydA==?= | last post by:
I read from a serialport using a worker thread. Because the worker thread t does not loop often, I cannot wait to terminate the worker thread using a boolean in the While condition. So I have a StopReader() method that simply aborts the worker thread (is there a better way for the above situation?). The StopReader creates an...
4
2044
by: dgleeson3 | last post by:
Hello all Yes I know its been done before, but something silly is killing me on this. I have the standard progress bar and worker thread scenario with progress of the worker thread being fed back to the main UI and displayed on the progress bar. I have a delegate and am using BeginInvoke. But the progress bar is not updating.
0
7733
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7957
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
8155
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
0
8001
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
6338
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5527
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
5248
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3673
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
976
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.