Multithread Revisted

D

Derek Hart

On the main thread I have a status bar in a Windows form that I want to
update when a long database process runs. The database process runs on a
separate thread:



Dim t As New Thread(AddressOf SomeDatabaseProcess)

t.Start()



The database process will be called about 10 times in one long routine,
starting a new thread each time. But the problem is that I need the thread
to finish before code execution continues. The main reason this does not
just run on the same thread is that I need to get the darn status bar
updated, but the UI freezes up. I tried using t.Join() which does wait for
the thread to finish, but it does not allow the UI to be freed up. And I
tried setting a global variable to detect when the thread is done, but the
code after the thread just runs in a Do Loop until the variable is set,
which also freezes up the UI. Any ideas of how to get this working?


Derek
 
G

GhostInAK

Hello Derek,

The reason the UI becomes unresponsive is that the long database operations
block the message pump. Instead of spinning off new threads, which are unneeded,
just massage the message pump immediately after updating the status bar.
(See MSDN documentation for application.DoEvents)

-Boo
 
M

Mehdi

The database process will be called about 10 times in one long routine,
starting a new thread each time. But the problem is that I need the thread
to finish before code execution continues. The main reason this does not
just run on the same thread is that I need to get the darn status bar
updated, but the UI freezes up. I tried using t.Join() which does wait for
the thread to finish, but it does not allow the UI to be freed up. And I
tried setting a global variable to detect when the thread is done, but the
code after the thread just runs in a Do Loop until the variable is set,
which also freezes up the UI. Any ideas of how to get this working?

Do all your database stuff in a single thread and use Control.Invoke or
Control.BeginInvoke to update your progress bar. These methods will
marshall the call to the UI thread for you. A lot cleaner than these ugly
hacks with Application.DoEvent loops dating from VB6.
 
G

Guest

Hello derek

so you want a responsive progressbar huh :)

i use the following

Delegate Sub AsynchMethodInvoker()
Public Sub SetPbValue(ByVal Count As Integer)
If Me.pbMain.InvokeRequired Then
Dim d As New CrossThreadInvParaMB(AddressOf SetPbValue)
Me.Invoke(d, New Object() {Count})
Else
Me.pbMain.Value = Count
End If
End Sub

now just call the method from your other thread and it will just work fine
:)

ofcourse is pbmain the progress bar


hope this helps


Michel Posseth [MCP]
 
G

Guest

if you want a responsive UI , one that is capable of terminating a hughe
update for instance , and the ability to perform simultanious tasks like
updating a progressbar that gives reall info , and a UI that repainst itself
after moving the form etc etc well then you can only acomplish this with
multithreading

The dissadvantage of using asynchronous code is that it is usualy slower as
synchronous code , however how slow is it when the user terminates the
program because he believes it doesn`t run at all because it is unresponsive

application.doevents is overdone in almost all situations you could better
call a refresh on the control


regards

Michel Posseth [MCP]
 
G

Guest

ahum :-(

copied the wrong delegate
Delegate Sub AsynchMethodInvoker()

should be

Delegate Sub CrossThreadInvParaMB(ByVal val As Integer)

sorry ;-)


M. Posseth said:
Hello derek

so you want a responsive progressbar huh :)

i use the following

Delegate Sub AsynchMethodInvoker()
Public Sub SetPbValue(ByVal Count As Integer)
If Me.pbMain.InvokeRequired Then
Dim d As New CrossThreadInvParaMB(AddressOf SetPbValue)
Me.Invoke(d, New Object() {Count})
Else
Me.pbMain.Value = Count
End If
End Sub

now just call the method from your other thread and it will just work fine
:)

ofcourse is pbmain the progress bar


hope this helps


Michel Posseth [MCP]







Mehdi said:
Do all your database stuff in a single thread and use Control.Invoke or
Control.BeginInvoke to update your progress bar. These methods will
marshall the call to the UI thread for you. A lot cleaner than these ugly
hacks with Application.DoEvent loops dating from VB6.
 
C

Cor Ligthert [MVP]

Michel
application.doevents is overdone in almost all situations you could better
call a refresh on the control
But you see than in my idea in the by the OPr explained sample only the
control, which is AFAIK done by the progressbar itself.

:)

Cor

M. Posseth said:
if you want a responsive UI , one that is capable of terminating a hughe
update for instance , and the ability to perform simultanious tasks like
updating a progressbar that gives reall info , and a UI that repainst
itself
after moving the form etc etc well then you can only acomplish this with
multithreading

The dissadvantage of using asynchronous code is that it is usualy slower
as
synchronous code , however how slow is it when the user terminates the
program because he believes it doesn`t run at all because it is
unresponsive

application.doevents is overdone in almost all situations you could better
call a refresh on the control


regards

Michel Posseth [MCP]


GhostInAK said:
Hello Derek,

The reason the UI becomes unresponsive is that the long database
operations
block the message pump. Instead of spinning off new threads, which are
unneeded,
just massage the message pump immediately after updating the status bar.
(See MSDN documentation for application.DoEvents)

-Boo
 
G

Guest

Not it shouldn`t be necesary ,

i wrote a nice demo for the TS and for the sceptic people :)

take a form throw 2 buttons on it and a progressbar

call the progressbar pbmain


now copy paste this :

Imports System.Threading
Public Class Form1
Private Mvar_Cancell As Boolean
Friend Property Cancell() As Boolean
Get
Return Mvar_Cancell
End Get
Set(ByVal value As Boolean)
Mvar_Cancell = value
Me.Button1.Enabled = value
End Set
End Property
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Me.Cancell = False
With pbMain
.Value = 0
.Maximum = 100
.Minimum = 0
End With

Dim AsyncProcess As New AsynchMethodInvoker(AddressOf Me.pbLoop)
AsyncProcess.BeginInvoke(Nothing, Nothing)

AsyncProcess = New AsynchMethodInvoker(AddressOf Me.DoSomething)
AsyncProcess.BeginInvoke(Nothing, Nothing)

End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
Cancell = True
End Sub

Private Sub DoSomething()
Do While Not Me.Cancell
Debug.WriteLine("hello world")
Loop
End Sub
Delegate Sub CrossThreadInvParaMB(ByVal val As Integer)
Private Sub pbLoop()
Dim i As Integer
Do While Not Me.Cancell
Thread.Sleep(50)
i += 1
If i = 101 Then i = 0
SetPbValue(i)
Loop
i = 100
SetPbValue(i)
End Sub
Delegate Sub AsynchMethodInvoker()
Public Sub SetPbValue(ByVal Count As Integer)
If Me.pbMain.InvokeRequired Then
Dim d As New CrossThreadInvParaMB(AddressOf SetPbValue)
Try
Me.Invoke(d, New Object() {Count})
Catch ex As Exception

End Try
Else
Me.pbMain.Value = Count
End If
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As
System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Me.Cancell = True
End Sub
End Class


i hope this gives you all an idea in what i mean ,,, the method that is now
updating the progressbar runs in a seperate thread to make it even nicer i
run another worker thread wich prints hello world statements to the debug
window

these threads can comunicate to the progressbar through the SetPbValue method


i hope this gives the TS some new input to solve his problem








Cor Ligthert said:
Michel
application.doevents is overdone in almost all situations you could better
call a refresh on the control
But you see than in my idea in the by the OPr explained sample only the
control, which is AFAIK done by the progressbar itself.

:)

Cor

M. Posseth said:
if you want a responsive UI , one that is capable of terminating a hughe
update for instance , and the ability to perform simultanious tasks like
updating a progressbar that gives reall info , and a UI that repainst
itself
after moving the form etc etc well then you can only acomplish this with
multithreading

The dissadvantage of using asynchronous code is that it is usualy slower
as
synchronous code , however how slow is it when the user terminates the
program because he believes it doesn`t run at all because it is
unresponsive

application.doevents is overdone in almost all situations you could better
call a refresh on the control


regards

Michel Posseth [MCP]


GhostInAK said:
Hello Derek,

The reason the UI becomes unresponsive is that the long database
operations
block the message pump. Instead of spinning off new threads, which are
unneeded,
just massage the message pump immediately after updating the status bar.
(See MSDN documentation for application.DoEvents)

-Boo

On the main thread I have a status bar in a Windows form that I want
to update when a long database process runs. The database process
runs on a separate thread:

Dim t As New Thread(AddressOf SomeDatabaseProcess)

t.Start()

The database process will be called about 10 times in one long
routine, starting a new thread each time. But the problem is that I
need the thread to finish before code execution continues. The main
reason this does not just run on the same thread is that I need to get
the darn status bar updated, but the UI freezes up. I tried using
t.Join() which does wait for the thread to finish, but it does not
allow the UI to be freed up. And I tried setting a global variable to
detect when the thread is done, but the code after the thread just
runs in a Do Loop until the variable is set, which also freezes up the
UI. Any ideas of how to get this working?

Derek
 
C

Cor Ligthert [MVP]

My dear Michel,

I only did mean that

I see that nowhere in your code.

If that is done to refresh and the form as it is hidden by another program, than it will not help, so it is neither a solution.

:)

Cor



M. Posseth said:
Not it shouldn`t be necesary ,

i wrote a nice demo for the TS and for the sceptic people :)

take a form throw 2 buttons on it and a progressbar

call the progressbar pbmain


now copy paste this :

Imports System.Threading
Public Class Form1
Private Mvar_Cancell As Boolean
Friend Property Cancell() As Boolean
Get
Return Mvar_Cancell
End Get
Set(ByVal value As Boolean)
Mvar_Cancell = value
Me.Button1.Enabled = value
End Set
End Property
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Me.Cancell = False
With pbMain
.Value = 0
.Maximum = 100
.Minimum = 0
End With

Dim AsyncProcess As New AsynchMethodInvoker(AddressOf Me.pbLoop)
AsyncProcess.BeginInvoke(Nothing, Nothing)

AsyncProcess = New AsynchMethodInvoker(AddressOf Me.DoSomething)
AsyncProcess.BeginInvoke(Nothing, Nothing)

End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
Cancell = True
End Sub

Private Sub DoSomething()
Do While Not Me.Cancell
Debug.WriteLine("hello world")
Loop
End Sub
Delegate Sub CrossThreadInvParaMB(ByVal val As Integer)
Private Sub pbLoop()
Dim i As Integer
Do While Not Me.Cancell
Thread.Sleep(50)
i += 1
If i = 101 Then i = 0
SetPbValue(i)
Loop
i = 100
SetPbValue(i)
End Sub
Delegate Sub AsynchMethodInvoker()
Public Sub SetPbValue(ByVal Count As Integer)
If Me.pbMain.InvokeRequired Then
Dim d As New CrossThreadInvParaMB(AddressOf SetPbValue)
Try
Me.Invoke(d, New Object() {Count})
Catch ex As Exception

End Try
Else
Me.pbMain.Value = Count
End If
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As
System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Me.Cancell = True
End Sub
End Class


i hope this gives you all an idea in what i mean ,,, the method that is now
updating the progressbar runs in a seperate thread to make it even nicer i
run another worker thread wich prints hello world statements to the debug
window

these threads can comunicate to the progressbar through the SetPbValue method


i hope this gives the TS some new input to solve his problem








Cor Ligthert said:
Michel
application.doevents is overdone in almost all situations you could better
call a refresh on the control
But you see than in my idea in the by the OPr explained sample only the
control, which is AFAIK done by the progressbar itself.

:)

Cor

M. Posseth said:
if you want a responsive UI , one that is capable of terminating a hughe
update for instance , and the ability to perform simultanious tasks like
updating a progressbar that gives reall info , and a UI that repainst
itself
after moving the form etc etc well then you can only acomplish this with
multithreading

The dissadvantage of using asynchronous code is that it is usualy slower
as
synchronous code , however how slow is it when the user terminates the
program because he believes it doesn`t run at all because it is
unresponsive

application.doevents is overdone in almost all situations you could better
call a refresh on the control


regards

Michel Posseth [MCP]


:

Hello Derek,

The reason the UI becomes unresponsive is that the long database
operations
block the message pump. Instead of spinning off new threads, which are
unneeded,
just massage the message pump immediately after updating the status bar.
(See MSDN documentation for application.DoEvents)

-Boo

On the main thread I have a status bar in a Windows form that I want
to update when a long database process runs. The database process
runs on a separate thread:

Dim t As New Thread(AddressOf SomeDatabaseProcess)

t.Start()

The database process will be called about 10 times in one long
routine, starting a new thread each time. But the problem is that I
need the thread to finish before code execution continues. The main
reason this does not just run on the same thread is that I need to get
the darn status bar updated, but the UI freezes up. I tried using
t.Join() which does wait for the thread to finish, but it does not
allow the UI to be freed up. And I tried setting a global variable to
detect when the thread is done, but the code after the thread just
runs in a Do Loop until the variable is set, which also freezes up the
UI. Any ideas of how to get this working?

Derek
 
M

Michel Posseth [MCP]

Hi Cor ,,,

Sorry i was in a bit of a hurry ( on the job when i wrote the previous )
should have been

in wich i mend to call the refresh of the control as it should take care of
that itself
as i showed in my example code ( did you tried it )

this code performs 2 loops in 2 seperate methods that should normally block
a ui if it wasn`t written with asynchronous delegates
( even better there is no way you can run these 2 synchronous in the same
time ) but even with the hello world loop in synchronous modus
you càn not get the ui to respond ,,, my example code shows a responsive ui
with a updating progressbar without doevents or a refresh call

as assiging the new value will take care of that as the ui is in a
responsive modus

so this also proves your statement ( that it should not be necesary to call
the refresh method of the control )


regards

Michel









"Cor Ligthert [MVP]" <[email protected]> schreef in bericht
My dear Michel,

I only did mean that

I see that nowhere in your code.

If that is done to refresh and the form as it is hidden by another program,
than it will not help, so it is neither a solution.

:)

Cor



M. Posseth said:
Not it shouldn`t be necesary ,

i wrote a nice demo for the TS and for the sceptic people :)

take a form throw 2 buttons on it and a progressbar

call the progressbar pbmain


now copy paste this :

Imports System.Threading
Public Class Form1
Private Mvar_Cancell As Boolean
Friend Property Cancell() As Boolean
Get
Return Mvar_Cancell
End Get
Set(ByVal value As Boolean)
Mvar_Cancell = value
Me.Button1.Enabled = value
End Set
End Property
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Me.Cancell = False
With pbMain
.Value = 0
.Maximum = 100
.Minimum = 0
End With

Dim AsyncProcess As New AsynchMethodInvoker(AddressOf Me.pbLoop)
AsyncProcess.BeginInvoke(Nothing, Nothing)

AsyncProcess = New AsynchMethodInvoker(AddressOf Me.DoSomething)
AsyncProcess.BeginInvoke(Nothing, Nothing)

End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
Cancell = True
End Sub

Private Sub DoSomething()
Do While Not Me.Cancell
Debug.WriteLine("hello world")
Loop
End Sub
Delegate Sub CrossThreadInvParaMB(ByVal val As Integer)
Private Sub pbLoop()
Dim i As Integer
Do While Not Me.Cancell
Thread.Sleep(50)
i += 1
If i = 101 Then i = 0
SetPbValue(i)
Loop
i = 100
SetPbValue(i)
End Sub
Delegate Sub AsynchMethodInvoker()
Public Sub SetPbValue(ByVal Count As Integer)
If Me.pbMain.InvokeRequired Then
Dim d As New CrossThreadInvParaMB(AddressOf SetPbValue)
Try
Me.Invoke(d, New Object() {Count})
Catch ex As Exception

End Try
Else
Me.pbMain.Value = Count
End If
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As
System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Me.Cancell = True
End Sub
End Class


i hope this gives you all an idea in what i mean ,,, the method that is
now
updating the progressbar runs in a seperate thread to make it even nicer i
run another worker thread wich prints hello world statements to the debug
window

these threads can comunicate to the progressbar through the SetPbValue
method


i hope this gives the TS some new input to solve his problem








Cor Ligthert said:
Michel
application.doevents is overdone in almost all situations you could
better
call a refresh on the control
But you see than in my idea in the by the OPr explained sample only the
control, which is AFAIK done by the progressbar itself.

:)

Cor

M. Posseth said:
if you want a responsive UI , one that is capable of terminating a
hughe
update for instance , and the ability to perform simultanious tasks
like
updating a progressbar that gives reall info , and a UI that repainst
itself
after moving the form etc etc well then you can only acomplish this
with
multithreading

The dissadvantage of using asynchronous code is that it is usualy
slower
as
synchronous code , however how slow is it when the user terminates the
program because he believes it doesn`t run at all because it is
unresponsive

application.doevents is overdone in almost all situations you could
better
call a refresh on the control


regards

Michel Posseth [MCP]


:

Hello Derek,

The reason the UI becomes unresponsive is that the long database
operations
block the message pump. Instead of spinning off new threads, which
are
unneeded,
just massage the message pump immediately after updating the status
bar.
(See MSDN documentation for application.DoEvents)

-Boo

On the main thread I have a status bar in a Windows form that I want
to update when a long database process runs. The database process
runs on a separate thread:

Dim t As New Thread(AddressOf SomeDatabaseProcess)

t.Start()

The database process will be called about 10 times in one long
routine, starting a new thread each time. But the problem is that I
need the thread to finish before code execution continues. The main
reason this does not just run on the same thread is that I need to
get
the darn status bar updated, but the UI freezes up. I tried using
t.Join() which does wait for the thread to finish, but it does not
allow the UI to be freed up. And I tried setting a global variable
to
detect when the thread is done, but the code after the thread just
runs in a Do Loop until the variable is set, which also freezes up
the
UI. Any ideas of how to get this working?

Derek
 
C

Cor Ligthert [MVP]

Michel,

I have not any doubt if you made it and shows it that it works, and even if
it does not work that it is a typo.

:)

Cor

Michel Posseth said:
Hi Cor ,,,

Sorry i was in a bit of a hurry ( on the job when i wrote the previous )
should have been

in wich i mend to call the refresh of the control as it should take care
of that itself
as i showed in my example code ( did you tried it )

this code performs 2 loops in 2 seperate methods that should normally
block a ui if it wasn`t written with asynchronous delegates
( even better there is no way you can run these 2 synchronous in the same
time ) but even with the hello world loop in synchronous modus
you càn not get the ui to respond ,,, my example code shows a responsive
ui with a updating progressbar without doevents or a refresh call

as assiging the new value will take care of that as the ui is in a
responsive modus

so this also proves your statement ( that it should not be necesary to
call the refresh method of the control )


regards

Michel









"Cor Ligthert [MVP]" <[email protected]> schreef in bericht
My dear Michel,

I only did mean that

I see that nowhere in your code.

If that is done to refresh and the form as it is hidden by another
program, than it will not help, so it is neither a solution.

:)

Cor



M. Posseth said:
Not it shouldn`t be necesary ,

i wrote a nice demo for the TS and for the sceptic people :)

take a form throw 2 buttons on it and a progressbar

call the progressbar pbmain


now copy paste this :

Imports System.Threading
Public Class Form1
Private Mvar_Cancell As Boolean
Friend Property Cancell() As Boolean
Get
Return Mvar_Cancell
End Get
Set(ByVal value As Boolean)
Mvar_Cancell = value
Me.Button1.Enabled = value
End Set
End Property
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Me.Cancell = False
With pbMain
.Value = 0
.Maximum = 100
.Minimum = 0
End With

Dim AsyncProcess As New AsynchMethodInvoker(AddressOf Me.pbLoop)
AsyncProcess.BeginInvoke(Nothing, Nothing)

AsyncProcess = New AsynchMethodInvoker(AddressOf Me.DoSomething)
AsyncProcess.BeginInvoke(Nothing, Nothing)

End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
Cancell = True
End Sub

Private Sub DoSomething()
Do While Not Me.Cancell
Debug.WriteLine("hello world")
Loop
End Sub
Delegate Sub CrossThreadInvParaMB(ByVal val As Integer)
Private Sub pbLoop()
Dim i As Integer
Do While Not Me.Cancell
Thread.Sleep(50)
i += 1
If i = 101 Then i = 0
SetPbValue(i)
Loop
i = 100
SetPbValue(i)
End Sub
Delegate Sub AsynchMethodInvoker()
Public Sub SetPbValue(ByVal Count As Integer)
If Me.pbMain.InvokeRequired Then
Dim d As New CrossThreadInvParaMB(AddressOf SetPbValue)
Try
Me.Invoke(d, New Object() {Count})
Catch ex As Exception

End Try
Else
Me.pbMain.Value = Count
End If
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As
System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
Me.Cancell = True
End Sub
End Class


i hope this gives you all an idea in what i mean ,,, the method that is
now
updating the progressbar runs in a seperate thread to make it even nicer
i
run another worker thread wich prints hello world statements to the debug
window

these threads can comunicate to the progressbar through the SetPbValue
method


i hope this gives the TS some new input to solve his problem








Cor Ligthert said:
Michel

application.doevents is overdone in almost all situations you could
better
call a refresh on the control

But you see than in my idea in the by the OPr explained sample only the
control, which is AFAIK done by the progressbar itself.

:)

Cor

"M. Posseth" <[email protected]> schreef in bericht

if you want a responsive UI , one that is capable of terminating a
hughe
update for instance , and the ability to perform simultanious tasks
like
updating a progressbar that gives reall info , and a UI that repainst
itself
after moving the form etc etc well then you can only acomplish this
with
multithreading

The dissadvantage of using asynchronous code is that it is usualy
slower
as
synchronous code , however how slow is it when the user terminates the
program because he believes it doesn`t run at all because it is
unresponsive

application.doevents is overdone in almost all situations you could
better
call a refresh on the control


regards

Michel Posseth [MCP]


:

Hello Derek,

The reason the UI becomes unresponsive is that the long database
operations
block the message pump. Instead of spinning off new threads, which
are
unneeded,
just massage the message pump immediately after updating the status
bar.
(See MSDN documentation for application.DoEvents)

-Boo

On the main thread I have a status bar in a Windows form that I
want
to update when a long database process runs. The database process
runs on a separate thread:

Dim t As New Thread(AddressOf SomeDatabaseProcess)

t.Start()

The database process will be called about 10 times in one long
routine, starting a new thread each time. But the problem is that
I
need the thread to finish before code execution continues. The
main
reason this does not just run on the same thread is that I need to
get
the darn status bar updated, but the UI freezes up. I tried using
t.Join() which does wait for the thread to finish, but it does not
allow the UI to be freed up. And I tried setting a global variable
to
detect when the thread is done, but the code after the thread just
runs in a Do Loop until the variable is set, which also freezes up
the
UI. Any ideas of how to get this working?

Derek
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top