Threading...

S

Simon Verona

I think I'm doing this wrong :

I have a class with a public shared method such as follows:

public shared sub myFunction
dim frm as new myFrm
dim t as new Threading.Thread(Addressof myFrm.myShowDialog
t.start
end sub

In the frm - the myShowDialog just does a "me.showdialog".

The idea is that this function will display a form, but then return control
back to the calling routine immediately without waiting for the form to be
closed.

It works, but I've had several reports of the form that is displayed
"crashing" as it is being displayed, with random errors (I've not got a
sample) or the whole application just disappearing (without error).

Can anybody assist, either by confirming or otherwise that what I'm doing is
reasonable, or perhaps letting me know a better way.

Regards
Simon

ps Previously posted by mistake to vb.controls group.

--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011



--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011
 
G

Guest

well im kinda curious on why it looks like your attempting to show another
form on a different thread....are you meaning to put the form on another
thread, and if so why?
 
L

Larry Lard

Simon said:
I think I'm doing this wrong :

I have a class with a public shared method such as follows:

public shared sub myFunction
dim frm as new myFrm
dim t as new Threading.Thread(Addressof myFrm.myShowDialog
t.start
end sub

In the frm - the myShowDialog just does a "me.showdialog".

The idea is that this function will display a form, but then return control
back to the calling routine immediately without waiting for the form to be
closed.

If this is what you want, why not just .Show (rather than .ShowDialog)
the form? Anyway...
It works, but I've had several reports of the form that is displayed
"crashing" as it is being displayed, with random errors (I've not got a
sample) or the whole application just disappearing (without error).

Can anybody assist, either by confirming or otherwise that what I'm doing is
reasonable, or perhaps letting me know a better way.

I think you are falling foul of the rule whereby UI elements cannot be
safely interacted with from threads other than their 'owning' thread -
that on which they are created. So here the myFrm is created on the
thread that enters this procedure, but then passed to a different
thread to show itself. Thus this second thread will be accessing UI
elements it didn't create -> bad.

The fix (if there are deeper reasons why you need to do this sort of
thing) is to move the form creation from before thread-creation to
after it. That is, at the moment you are saying:

Create form
Create thread (giving it the form)
Start thread - thread goes on to show form

Instead you should say

Create thread
Start thread - thread goes on to create form, then show it.

Probably the logical place for this new routine would be a Shared
procedure in myFrm:

Public Shared Sub NewShowDialog
Dim f As New myFrm
f.ShowDialog
End Sub

then replace your current myFunction with

Dim t As New Thread(AddressOf myFrm.NewShowDialog)
t.Start

But please first consider my first question about .Show vs
..ShowDialog...
 
S

Simon Verona

Good question...

Maybe if I explain the application....

I have a main form, which displays a list of entries. The application
allows you to click on an entry to open a form to view/update the details of
that entry.

However, I wanted to allow multiple entries to be displayed together.

Also, I wanted to encapsulate the display of the form within a class (it is
used in many parts of the application as well, so I felt it would be
easier).

If I display the form without creating the thread, the form dies as soon as
the subroutine exits back to the main form (IIRC!), so I came up with this
as a workaround. It also seemed to have the affect of making the
application seem to run smoother (though that could just be me). If I don't
create the thread and just use showdialog, then the original form is blocked
until it returns.

I don't know why it should be causing a problem, but if there is a better
way of acheiving the same thing without creating the thread then I'm up for
it!

Regards
Simon



--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011
 
S

Simon Verona

See my previous reply, I've had problem with the form disappearing when the
subroutine exits... (I'm presuming the object is killed on exit?)

I understand what you are saying about the frm creation and use being on
seperate threads. I must admit to not thinking of having a shared entry on
the form to display itself!

Regards
Simon

--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011
 
G

Guest

if you want to show a new form on a different thread, then the new thread
must then create the form object:

Private Delegate Sub delNewThread

Private Sub btnNewThread_Click(...)

Dim x as New delNewThread(AddressOf CreateNewFormThreadBegin)

Me.Invoke(x)

End Sub

Private Sub CreateNewFormThreadBegin()

Dim frm as New Form2

frm.ShowDialog()

End Sub


that will create a new form on a different thread then show it
 
G

Guest

well, if you wan to do it that way, then make sure our thread safe. Threads
can only access objects they create, for instance your Form1 cannot access
things on your other thread's form and vice versa, keep that in mind. To
access methods on other threads, use the threads Invoke method, dont call the
method directly. Keeping that in mind, there wouldnt be a need to call
"ShowDialog" and show the form on a new thread....i dont know if that would
cause issues or not, so your best bet would be calling "Show", not
"ShowDialog"
 
S

Simon Verona

Larry

I had a go at implementing your thought, but of course, the "real" code is
not quite as simple as the example I posted:

The real code passes a variable through to the form when constructing ie

dim frm as new myfrm(myvar)
dim t as new threading.thread(addressof frm.myShowDialog)
t.start

I can't work out how to create a shared function that I can call on another
thread AND pass a parameter!

Regards
Simon

--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011
 
S

Simon Verona

Thanks for the example...

However, I'm not 100% positive how I would modify your example to pass a
variable to the form.

I presume that I can't set a local private variable (declared outside of ay
subroutines) and then access it from within the CreateNewFormThreadBegin
sub? I'm presuming that can I can't directly pass any variables directly
through to the CreateNewFromThreadBegin (ie modifying it to Private Sub
CreateNewFromThreadBegin(myvar as string) )

Apologies if I've missed the obvious - Can I use the facts that it's 5pm and
very hot to mitigate my stupidity? <G>

Thanks
Simon

--
================================
Simon Verona
Dealer Management Service Ltd
Stewart House
Centurion Business Park
Julian Way
Sheffield
S9 1GD

Tel: 0870 080 2300
Fax: 0870 735 0011
 
G

Guest

i appologize, i forgot to add the code to create a thread..silly me, heres
the updated code, im working on pass variables now...i forgot how to do it
myself


Private Delegate Sub delNewThreadBegin()


Private Sub NewThreadBeginSub()

Dim frm As New Form1

frm.ShowDialog()

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click

Dim thr As New Threading.Thread(AddressOf ThreadStart)

thr.Start()

End Sub

Private Sub ThreadStart()

Dim x As New delNewThreadBegin(AddressOf NewThreadBeginSub)

Me.Invoke(x)

End Sub
 
G

Guest

i cant figure it out rite now, im a 17 year old at work trying to multi task
and its nto working too well so my code doesnt even make sense to me....il
write the answer when i get home, i have a few examples on my home computer
 
L

Larry Lard

Simon said:
See my previous reply, I've had problem with the form disappearing when the
subroutine exits... (I'm presuming the object is killed on exit?)

I'd be tempted to go back and re-examine that situation, to be honest.
To paint with a *very* broad brush, multi-threading is something you
shouldn't do unless you quite obviously _must_.
I understand what you are saying about the frm creation and use being on
seperate threads. I must admit to not thinking of having a shared entry on
the form to display itself!

The thought process there was that the behaviour of <creating a new
myFrm and displaying it> clearly 'belongs to' the myFrm class, but not
to any particular instance of it => shared method.
 
T

Tom Shelton

Simon said:
I think I'm doing this wrong :

I have a class with a public shared method such as follows:

public shared sub myFunction
dim frm as new myFrm
dim t as new Threading.Thread(Addressof myFrm.myShowDialog
t.start
end sub

In the frm - the myShowDialog just does a "me.showdialog".

The idea is that this function will display a form, but then return control
back to the calling routine immediately without waiting for the form to be
closed.

It works, but I've had several reports of the form that is displayed
"crashing" as it is being displayed, with random errors (I've not got a
sample) or the whole application just disappearing (without error).

Can anybody assist, either by confirming or otherwise that what I'm doing is
reasonable, or perhaps letting me know a better way.

Simon...

All of this really depends on your architecture. Is this routine that
is showing the form on a background thread? If it is, that would
explain why the form exits when the routine ends. If it is on a
background thread, there is no message pump and the form will exit when
the routine ends because the thread exits.

Here is three different methods of showing a form:

Option Strict On
Option Explicit On

Imports System
Imports System.Threading
Imports System.Runtime.InteropServices


Public Class Form1
Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form
Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents Button1 As System.Windows.Forms.Button
Friend WithEvents Button2 As System.Windows.Forms.Button
Friend WithEvents Button3 As System.Windows.Forms.Button
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button
Me.Button2 = New System.Windows.Forms.Button
Me.Button3 = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(0, 0)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(328, 23)
Me.Button1.TabIndex = 0
Me.Button1.Text = "Show Form On Current Thread (Form.Show)"
'
'Button2
'
Me.Button2.Location = New System.Drawing.Point(0, 28)
Me.Button2.Name = "Button2"
Me.Button2.Size = New System.Drawing.Size(328, 23)
Me.Button2.TabIndex = 1
Me.Button2.Text = "Show Form On New Thread (Application.Run)"
'
'Button3
'
Me.Button3.Location = New System.Drawing.Point(0, 56)
Me.Button3.Name = "Button3"
Me.Button3.Size = New System.Drawing.Size(328, 23)
Me.Button3.TabIndex = 2
Me.Button3.Text = "Show Form On New Thread (ShowDialog)"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(328, 82)
Me.Controls.Add(Me.Button3)
Me.Controls.Add(Me.Button2)
Me.Controls.Add(Me.Button1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)

End Sub

#End Region

<DllImport("kernel32")> _
Public Shared Function GetCurrentThreadId() As IntPtr

End Function

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim frm As New Form2
frm.Show()
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
Dim thrd As New Thread(AddressOf ShowFormAppRun)
thrd.ApartmentState = ApartmentState.STA
thrd.Start()
End Sub

Private Sub ShowFormAppRun()
Dim frm As New Form2
Application.Run(frm)
End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button3.Click

Dim thrd As New Thread(AddressOf ShowFormDialog)
thrd.ApartmentState = ApartmentState.STA
thrd.Start()

End Sub

Private Sub ShowFormDialog()
Dim frm As New Form2
frm.ShowDialog()
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Me.Text = String.Format("Main Form - Thread ID {0}",
Form1.GetCurrentThreadId())
End Sub
End Class

Public Class Form2
Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form
Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
'
'Form2
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 30)
Me.Name = "Form2"
Me.Text = "Form2"

End Sub

#End Region

Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Me.Text = String.Format("Child Form - Thread ID {0}",
Form1.GetCurrentThreadId())
End Sub
End Class


There are two forms here, so look out if you copy paste the code. If
you don't find this stuff usefull, maybe you can post some code that
demonstrates more of your problem...
 
B

Branco Medeiros

Simon Verona wrote:
I have a class with a public shared method such as follows:

public shared sub myFunction
dim frm as new myFrm
dim t as new Threading.Thread(Addressof myFrm.myShowDialog
t.start
end sub

In the frm - the myShowDialog just does a "me.showdialog".

The idea is that this function will display a form, but then return control
back to the calling routine immediately without waiting for the form to be
closed.

It works, but I've had several reports of the form that is displayed
"crashing" as it is being displayed, with random errors (I've not got a
sample) or the whole application just disappearing (without error).
<snip>

It's an error to access the method of a class derived from Control
(which is the case of Form) from a thread other than the one where the
object was created. You must use the object's InvokeRequired method to
check if you're being called from another thread and if so
(InvokeRequired returned True), use Invoke to call the desired method.
The 'pattern' is somewhat like this:

'in myForm
'Must have the same signature of MyShowDialog
Delegate Sub MyShowDialogCallback(Param as Integer)
'...
Sub MyShowDialog(Param As Integer)
Static This As MyShowDialogCallback = AddressOf MyShowDialog
If InvokeRequired Then
BeginInvoke(This, New Object() {Param} )
Else
'Do your thing
'blah, blah, blah
ShowDialog
End If
End Sub

HTH.

Regards,

Branco.
 

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