threading questions

  • Thread starter Thread starter ChunkyMonkey
  • Start date Start date
C

ChunkyMonkey

Howdy

In my startup form, I start up a thread for a function that I want to run in
the background(the function just polls a system every second). See first
section of code below.

What I am doing at the moment, is in the new thread, I load a form, and this
form has a timer that when it ticks, get the status of a remote machine. At
the moment on every tick, it add an item to a list box which is just the
now() value so that I can see it working

This all works fine.

The issue is that I want the new thread that is polling the machine, to
update the main thread, and call a function in my startup form.

I tried in my timer event, to call the public function in my startup form,
just passing some text, but nothing happens.

What do I need to do, so that the new thread can call functions on the
frmMain...



Code:
--------
'Startup Form(frmMain) code creating new thread....

Dim PollingThread As New Thread(AddressOf PollLift)
PollingThread.IsBackground = True
PollingThread.Name = "Polling"
PollingThread.Start()
--------------
Public Function PollLift() As Boolean

Dim frmPolling As New frmComms
frmPolling.ShowDialog()
frmPolling.Timer1.Enabled = True

End Function


' in the frmPolling form there is a timer..
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Timer1.Tick

ListBox1.Items.Add("Tick" & Now)
frmMain.LiftUpdate(Now)

End Sub

' in the frmMain....
Public Function LiftUpdate(ByVal strText As String)
lblThread.Text = strText
End Function
 
Howdy

In my startup form, I start up a thread for a function that I want to runin
the background(the function just polls a system every second). See first
section of code below.

What I am doing at the moment, is in the new thread, I load a form, and this
form has a timer that when it ticks, get the status of a remote machine. At
the moment on every tick, it add an item to a list box which is just the
now() value so that I can see it working

You cannot create a new Form in a worker thread and expect everything
to work correctly. The problem is that your worker thread will not be
running a message loop. Windows forms and controls do not work
correctly without the message loop.
This all works fine.

It may appear to work fine, but all is not good.
The issue is that I want the new thread that is polling the machine, to
update the main thread, and call a function in my startup form.

I tried in my timer event, to call the public function in my startup form,
just passing some text, but nothing happens.

What do I need to do, so that the new thread can call functions on the
frmMain...

You will need to use the ISynchronizeInvoke interface on the startup
form to accomplish this. That interfaces exposes Invoke and
BeginInvoke methods that both accept a delegate as a parameter. The
execution of that delegate is marshalled onto the thread hosting the
target object (usually a form or control).

I would avoid creating the frmComms form on the worker thread. It
really needs be created and used on the main UI thread. The polling
of the system can be accomplished in several ways, but if you want to
continue with the worker thread design then you could create an
infinite loop on it that calls Thread.Sleep at the desired intervals.
After Thread.Sleep returns then the thread could execute the desired
logic and report its progress to the UI thread via calls to
Form.Invoke or Form.BeginInvoke.
 
HI,

Thanks for you feedback.

The idea of the new thread creating a new form, is probably not really
required if I think about it.

Would I make it all easier if instead of creating a new form, I just dealt
with a control on the main form ?

Could the new thread just then update a control on the frmMain, as the
thread was created from frmMain or is the invoke stuff still required ?

Thanks

Howdy

In my startup form, I start up a thread for a function that I want to run
in
the background(the function just polls a system every second). See first
section of code below.

What I am doing at the moment, is in the new thread, I load a form, and
this
form has a timer that when it ticks, get the status of a remote machine.
At
the moment on every tick, it add an item to a list box which is just the
now() value so that I can see it working

You cannot create a new Form in a worker thread and expect everything
to work correctly. The problem is that your worker thread will not be
running a message loop. Windows forms and controls do not work
correctly without the message loop.
This all works fine.

It may appear to work fine, but all is not good.
The issue is that I want the new thread that is polling the machine, to
update the main thread, and call a function in my startup form.

I tried in my timer event, to call the public function in my startup form,
just passing some text, but nothing happens.

What do I need to do, so that the new thread can call functions on the
frmMain...

You will need to use the ISynchronizeInvoke interface on the startup
form to accomplish this. That interfaces exposes Invoke and
BeginInvoke methods that both accept a delegate as a parameter. The
execution of that delegate is marshalled onto the thread hosting the
target object (usually a form or control).

I would avoid creating the frmComms form on the worker thread. It
really needs be created and used on the main UI thread. The polling
of the system can be accomplished in several ways, but if you want to
continue with the worker thread design then you could create an
infinite loop on it that calls Thread.Sleep at the desired intervals.
After Thread.Sleep returns then the thread could execute the desired
logic and report its progress to the UI thread via calls to
Form.Invoke or Form.BeginInvoke.
 
Howdy

In my startup form, I start up a thread for a function that I want to run in
the background(the function just polls a system every second). See first
section of code below.

What I am doing at the moment, is in the new thread, I load a form, and this
form has a timer that when it ticks, get the status of a remote machine. At
the moment on every tick, it add an item to a list box which is just the
now() value so that I can see it working

This all works fine.

The issue is that I want the new thread that is polling the machine, to
update the main thread, and call a function in my startup form.

I tried in my timer event, to call the public function in my startup form,
just passing some text, but nothing happens.

What do I need to do, so that the new thread can call functions on the
frmMain...



Code:
--------
'Startup Form(frmMain) code creating new thread....

Dim PollingThread As New Thread(AddressOf PollLift)
PollingThread.IsBackground = True
PollingThread.Name = "Polling"
PollingThread.Start()
--------------
Public Function PollLift() As Boolean

Dim frmPolling As New frmComms
frmPolling.ShowDialog()
frmPolling.Timer1.Enabled = True

End Function


' in the frmPolling form there is a timer..
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Timer1.Tick

ListBox1.Items.Add("Tick" & Now)
frmMain.LiftUpdate(Now)

End Sub

' in the frmMain....
Public Function LiftUpdate(ByVal strText As String)
lblThread.Text = strText
End Function

You know, all of this would be a lot simpler if used the appropriate timer :)
I would use a System.Threading.Timer for this. Simply create the timer and
start it - you don't need to explicitly start a thread, the tick even will
happen at the right intval on a threadpool thread.

The issue from there is then interacting with the main from from the tick
event. That requires a bit of magic, but nothing hard :)

Just use the forms invoke event and a delegate to call the update method
(which by the way should be a sub and not a function)

Something like (air code):

Public Sub LiftUpdate(ByVal strText As String)
lblThread.Text = strText
End Sub

Sub TimerTick (ByVal o As Object)

frmMain.Invoke (New Action(Of String)(AddressOf LiftUpdate), New
Object() {whateverText})
End Sub

Remember - you can not directly access any form controls from a background
thread. You must use the Invoke method and a delegate to marshal the calls
back to the main thread.
 
HI,

Thanks for you feedback.

The idea of the new thread creating a new form, is probably not really
required if I think about it.

Would I make it all easier if instead of creating a new form, I just dealt
with a control on the main form ?

Could the new thread just then update a control on the frmMain, as the
thread was created from frmMain or is the invoke stuff still required ?

Thanks

Nah, you'll still have do all of the Invoke stuff. You absolutely
cannot do *anything* with a form or control from a thread other than
the one that created it...no exceptions.

If you want to abandon the worker thread design you could use the
System.Windows.Forms.Timer. That timer raises its event on the UI
thread so you wouldn't even need to worry about the complexities of
threading. Of course, the disadvantage is that if you do too much
work on that timer's elapsed event then you run the risk of
overrunning the UI's message loop queue. The UI could become
unresponsive in that case.
 
ChunkyMonkey said:
Howdy

In my startup form, I start up a thread for a function that I want to run
in the background(the function just polls a system every second). See
first section of code below.

What I am doing at the moment, is in the new thread, I load a form, and
this form has a timer that when it ticks, get the status of a remote
machine. At the moment on every tick, it add an item to a list box which
is just the now() value so that I can see it working

This all works fine.

The issue is that I want the new thread that is polling the machine, to
update the main thread, and call a function in my startup form.

I tried in my timer event, to call the public function in my startup form,
just passing some text, but nothing happens.

What do I need to do, so that the new thread can call functions on the
frmMain...



Code:
--------
'Startup Form(frmMain) code creating new thread....

Dim PollingThread As New Thread(AddressOf PollLift)
PollingThread.IsBackground = True
PollingThread.Name = "Polling"
PollingThread.Start()
--------------
Public Function PollLift() As Boolean

Dim frmPolling As New frmComms
frmPolling.ShowDialog()
frmPolling.Timer1.Enabled = True

End Function


' in the frmPolling form there is a timer..
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Timer1.Tick

ListBox1.Items.Add("Tick" & Now)
frmMain.LiftUpdate(Now)

End Sub

' in the frmMain....
Public Function LiftUpdate(ByVal strText As String)
lblThread.Text = strText
End Function
Have you had a look at Component classes. They present a nice way of doing
things in the background.. Essentially, you make a call to them to do a job
and they raise user defined events that you handle at the UI interface. Some
of the possible events could be WorkComplete, ProgressChanged, ErrorMessage
etc, all up to you as you determine their behaviour. They appear in the
toolbox of the IDE after compilation and you can then drop them on any form
and execute their method.
Have serious look at these guys.
 
Back
Top