Why Does This Fail ( Threading )

  • Thread starter One Handed Man \( OHM - Terry Burns \)
  • Start date
O

One Handed Man \( OHM - Terry Burns \)

Assumes a Form with a Panel on it., Does the Mutex have to be within the
address of a thread start address ?

Cheers - OHM

'----------- *************** ----------------

Private endProgram As Boolean = False

Dim image1 As Image = Image.FromFile("..\Images\gun.bmp")

Dim image2 As Image = Image.FromFile("..\Images\Invader.bmp")

Dim space As Graphics

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



Dim Thread1 As New Threading.Thread(AddressOf Me.WriteImage1)

Dim Thread2 As New Threading.Thread(AddressOf Me.WriteImage2)

space = Panel1.CreateGraphics()

Thread1.Start()

Thread2.Start()

End Sub



Private Sub WriteImage1()

While Not endProgram

DrawImage(space, image1, New Point(10, 10))

End While

End Sub

Private Sub WriteImage2()

While Not endProgram

DrawImage(space, image2, New Point(50, 50))

End While

End Sub

Public Sub DrawImage(ByVal g As Graphics, ByVal i As Image, ByVal p As
Point)

Dim m As New Threading.Mutex

m.WaitOne()

g.DrawImage(i, p)

m.ReleaseMutex()

End Sub


--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
--
 
L

Larry Serflaten

One Handed Man ( OHM - Terry Burns ) said:
Assumes a Form with a Panel on it., Does the Mutex have to be within the
address of a thread start address ?

I would think it would have to be declared at a larger scope than the
procedure you need it in. I looks to me like you create and destroy a new
mutex for each call....

LFS
 
K

Ken Tucker [MVP]

Hi,

First cant update the ui from a thread.
http://msdn.microsoft.com/msdnmag/issues/04/05/BasicInstincts/

Second. You might be better of with synclock instead a mutex

Public Sub DrawImage(ByVal g As Graphics, ByVal i As Image, ByVal p As
Point)


synclock g

g.DrawImage(i, p)

end synclock
End Sub


Ken
-----------------
"One Handed Man ( OHM - Terry Burns )" <news.microsoft.com> wrote in message
Assumes a Form with a Panel on it., Does the Mutex have to be within the
address of a thread start address ?

Cheers - OHM

'----------- *************** ----------------

Private endProgram As Boolean = False

Dim image1 As Image = Image.FromFile("..\Images\gun.bmp")

Dim image2 As Image = Image.FromFile("..\Images\Invader.bmp")

Dim space As Graphics

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



Dim Thread1 As New Threading.Thread(AddressOf Me.WriteImage1)

Dim Thread2 As New Threading.Thread(AddressOf Me.WriteImage2)

space = Panel1.CreateGraphics()

Thread1.Start()

Thread2.Start()

End Sub



Private Sub WriteImage1()

While Not endProgram

DrawImage(space, image1, New Point(10, 10))

End While

End Sub

Private Sub WriteImage2()

While Not endProgram

DrawImage(space, image2, New Point(50, 50))

End While

End Sub

Public Sub DrawImage(ByVal g As Graphics, ByVal i As Image, ByVal p As
Point)

Dim m As New Threading.Mutex

m.WaitOne()

g.DrawImage(i, p)

m.ReleaseMutex()

End Sub


--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
--
 
C

CJ Taylor

Don't declare the mutex at the procedure level, perhaps try to at the
module/class level. Otherwise, each time you enter the procedure you create
a new (and unnamed) mutex variable which the other thread doesn't care
about. So of course it tries to write.

Alright, so after doing some more reading, was looking at the waithandle and
how that works. Look into AutoResetEvent, in which case its defined as the
threads communicating through events... I can help more in a minute, but
have to finish something else now and wanted to get this out to you. It
inherits from WaitHandle (same as Mutex waitone). but has a few more
options that do the dirty work under the sheets...

Check it out and let me know if it helps..
-CJ

I'll write more shortly.
 
O

One Handed Man \( OHM - Terry Burns \)

Tried decaling the Mutex in a module,that didnt work either

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
O

One Handed Man \( OHM - Terry Burns \)

tried Synclock, that doesent seem to work

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
O

One Handed Man \( OHM - Terry Burns \)

tried declaring at module level, that didnt work. Tried Synclock, that didnt
work either

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
--


CJ Taylor said:
Don't declare the mutex at the procedure level, perhaps try to at the
module/class level. Otherwise, each time you enter the procedure you
create
a new (and unnamed) mutex variable which the other thread doesn't care
about. So of course it tries to write.

Alright, so after doing some more reading, was looking at the waithandle
and
how that works. Look into AutoResetEvent, in which case its defined as
the
threads communicating through events... I can help more in a minute, but
have to finish something else now and wanted to get this out to you. It
inherits from WaitHandle (same as Mutex waitone). but has a few more
options that do the dirty work under the sheets...

Check it out and let me know if it helps..
-CJ

I'll write more shortly.


"One Handed Man ( OHM - Terry Burns )" <news.microsoft.com> wrote in
message
 
C

CJ Taylor

Try AutoResetEvent


One Handed Man ( OHM - Terry Burns ) said:
tried declaring at module level, that didnt work. Tried Synclock, that
didnt work either

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
O

One Handed Man \( OHM - Terry Burns \)

Same problem

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
L

Larry Serflaten

One Handed Man ( OHM - Terry Burns ) said:
Tried decaling the Mutex in a module,that didnt work either

I suggested using a delegate. Try this out in a new form with one button.
Paste in the code after the designer code.

Also as I was building this up, it occured to me that some sort of pooling
should be used, should it not? Invaders come and go over the course of the
game, so pooling may let the system managed them a little better....

HTH
LFS

Private GrxForm As Graphics
Private th1, th2 As Threading.Thread
Private brh As SolidBrush = New SolidBrush(Color.Black)
Private rnd As Random = New Random
Private fnt As Font = New Font("tahoma", 24, FontStyle.Bold)

Delegate Sub Drawing(ByVal ID As Integer, ByVal Loc As PointF)
Private Dlg As New Drawing(AddressOf CommonDraw)

Private Done As Boolean

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
GrxForm = Me.CreateGraphics
Th1 = New Threading.Thread(AddressOf Thread1)
Th2 = New Threading.Thread(AddressOf Thread2)
Th1.Start()
Th2.Start()
End Sub

Private Sub CommonDraw(ByVal ID As Integer, ByVal Loc As PointF)
Dim klr As Color = Color.FromArgb(200, rnd.Next(0, 256), rnd.Next(0, 256), rnd.Next(0, 256))
' The Brush, Font and Graphics are shared
brh.Color = klr
GrxForm.FillRectangle(brh, Loc.X, Loc.Y, 80, 50)
GrxForm.DrawString(CStr(ID), fnt, Brushes.Black, Loc)
End Sub

Sub Thread1()
Dim id As Integer = 1
Dim loc As PointF = New PointF(10, 10)
Do While Not Done
Me.Invoke(Dlg, New Object() {id, loc})
Threading.Thread.Sleep(100)
Loop
End Sub

Sub Thread2()
Dim id As Integer = 2
Dim loc As PointF = New PointF(100, 10)
Do While Not Done
Me.Invoke(Dlg, New Object() {id, loc})
Threading.Thread.Sleep(100)
Loop
End Sub

Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
e.Cancel = Done
Done = True
Application.DoEvents()
Th1.Abort()
Th2.Abort()
End Sub
 
L

Larry Serflaten

Larry Serflaten said:
Private Sub Form1_Closing(...)
e.Cancel = Done
Done = True
Application.DoEvents()
Th1.Abort()
Th2.Abort()
End Sub


Should have been:

e.Cancel = Not Done

It was meant to cause the first hit on the close button to stop the
threads (they take a while to close down) and the second hit to
close the form....

(Rather than add another button to stop the threads...)

LFS
 
O

One Handed Man \( OHM - Terry Burns \)

Thanks Larry,

I've tried your code out and it seems fine, I'll see if I can work it in to
my code and observe the results. Threading is not something Ive had to do
much of, so these kinds of issues have not arisen for me. It just goes to
show that real work problems provide the best excercies to promote learning.



--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
C

CJ Taylor

Alright... lets go into more detail... how is it failing...


One Handed Man ( OHM - Terry Burns ) said:
Same problem

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
--


"CJ Taylor" <cege [ahh ttt] tavayn wooohooo hooo ohhh com> wrote in message
Try AutoResetEvent


One Handed Man ( OHM - Terry Burns ) said:
tried declaring at module level, that didnt work. Tried Synclock, that
didnt work either

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
--


"CJ Taylor" <[cege] at [tavayn] dit commmmm> wrote in message
Don't declare the mutex at the procedure level, perhaps try to at the
module/class level. Otherwise, each time you enter the procedure you
create
a new (and unnamed) mutex variable which the other thread doesn't care
about. So of course it tries to write.

Alright, so after doing some more reading, was looking at the waithandle
and
how that works. Look into AutoResetEvent, in which case its defined as
the
threads communicating through events... I can help more in a minute,
but
have to finish something else now and wanted to get this out to you. It
inherits from WaitHandle (same as Mutex waitone). but has a few more
options that do the dirty work under the sheets...

Check it out and let me know if it helps..
-CJ

I'll write more shortly.


"One Handed Man ( OHM - Terry Burns )" <news.microsoft.com> wrote in
message
Assumes a Form with a Panel on it., Does the Mutex have to be within
the
address of a thread start address ?

Cheers - OHM

'----------- *************** ----------------

Private endProgram As Boolean = False

Dim image1 As Image = Image.FromFile("..\Images\gun.bmp")

Dim image2 As Image = Image.FromFile("..\Images\Invader.bmp")

Dim space As Graphics

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



Dim Thread1 As New Threading.Thread(AddressOf Me.WriteImage1)

Dim Thread2 As New Threading.Thread(AddressOf Me.WriteImage2)

space = Panel1.CreateGraphics()

Thread1.Start()

Thread2.Start()

End Sub



Private Sub WriteImage1()

While Not endProgram

DrawImage(space, image1, New Point(10, 10))

End While

End Sub

Private Sub WriteImage2()

While Not endProgram

DrawImage(space, image2, New Point(50, 50))

End While

End Sub

Public Sub DrawImage(ByVal g As Graphics, ByVal i As Image, ByVal p As
Point)

Dim m As New Threading.Mutex

m.WaitOne()

g.DrawImage(i, p)

m.ReleaseMutex()

End Sub


--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
O

One Handed Man \( OHM - Terry Burns \)

If you past my code into a form and add a panel etc, you will see. If comes
back with a "Object in use elsewhere", Larry posted some code which I tried
in the configuration in which he tested it and it seemed to work. I was
going to try it out in my code and see what transpires. I'm not particulary
experienced at threading so this is newish to me.

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
--


CJ Taylor said:
Alright... lets go into more detail... how is it failing...


"One Handed Man ( OHM - Terry Burns )" <news.microsoft.com> wrote in
message
Same problem

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
--


"CJ Taylor" <cege [ahh ttt] tavayn wooohooo hooo ohhh com> wrote in message
Try AutoResetEvent


"One Handed Man ( OHM - Terry Burns )" <news.microsoft.com> wrote in
message tried declaring at module level, that didnt work. Tried Synclock, that
didnt work either

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
--


"CJ Taylor" <[cege] at [tavayn] dit commmmm> wrote in message
Don't declare the mutex at the procedure level, perhaps try to at
the
module/class level. Otherwise, each time you enter the procedure you
create
a new (and unnamed) mutex variable which the other thread doesn't
care
about. So of course it tries to write.

Alright, so after doing some more reading, was looking at the waithandle
and
how that works. Look into AutoResetEvent, in which case its defined as
the
threads communicating through events... I can help more in a minute,
but
have to finish something else now and wanted to get this out to you. It
inherits from WaitHandle (same as Mutex waitone). but has a few more
options that do the dirty work under the sheets...

Check it out and let me know if it helps..
-CJ

I'll write more shortly.


"One Handed Man ( OHM - Terry Burns )" <news.microsoft.com> wrote in
message
Assumes a Form with a Panel on it., Does the Mutex have to be within
the
address of a thread start address ?

Cheers - OHM

'----------- *************** ----------------

Private endProgram As Boolean = False

Dim image1 As Image = Image.FromFile("..\Images\gun.bmp")

Dim image2 As Image = Image.FromFile("..\Images\Invader.bmp")

Dim space As Graphics

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



Dim Thread1 As New Threading.Thread(AddressOf Me.WriteImage1)

Dim Thread2 As New Threading.Thread(AddressOf Me.WriteImage2)

space = Panel1.CreateGraphics()

Thread1.Start()

Thread2.Start()

End Sub



Private Sub WriteImage1()

While Not endProgram

DrawImage(space, image1, New Point(10, 10))

End While

End Sub

Private Sub WriteImage2()

While Not endProgram

DrawImage(space, image2, New Point(50, 50))

End While

End Sub

Public Sub DrawImage(ByVal g As Graphics, ByVal i As Image, ByVal p As
Point)

Dim m As New Threading.Mutex

m.WaitOne()

g.DrawImage(i, p)

m.ReleaseMutex()

End Sub


--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
O

One Handed Man \( OHM - Terry Burns \)

Actually, thinking about this more before I try and implement it.

My Invader and Gun classes are responsible for doing their own drawing, in
this case they both have to use the/a delegate in which case perhaps I need
to raise an event as they do not have an Invoke method as a form does.

Sorry, but I feel really feel like I cant think my way out of a paper bag
today :(

--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
O

One Handed Man \( OHM - Terry Burns \)

Hi Larry,

I have implemented your solution in my code and it works. However, the way I
had to do this was to pass a reference of the form to the Class Invader and
Gun, this way I could do the Invoke of the method on the UI Thread in the
form.

Is this the way you would have done it ?

Thanks





--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 
L

Larry Serflaten

One Handed Man ( OHM - Terry Burns ) said:
I have implemented your solution in my code and it works. However, the way I
had to do this was to pass a reference of the form to the Class Invader and
Gun, this way I could do the Invoke of the method on the UI Thread in the
form.

Is this the way you would have done it ?


You are using a design I would have avoided. If you are trying to duplicate
'Space Invaders' then you'd have rows of aliens that march side to side as
they advance toward the player.

Because the whole row advances, and moves as a unit, I would have tried
to make a class that handles the whole row. In addition to fewer objects,
I'd be copying an image of the whole row over at a time, and not each
individual invader.

But, with that said, it may be this is more of an exercise in using threads,
which is OK, if that is what you are really after....

At first glance, it seems you should be using a collection (of some sort) to
house all the invaders that are currently being used. I would think the call
from the invaders should be made to their container, to interact with the
outside world. That would mean the invaders call on a method of their
collection object, who forwards their call to the form. That forwarding
routine should add a check to be sure the form reference is still valid
before forwarding the call.

While that may be a more refined approach, it may just be more practical
to make the form available globally (project wide) and let the invaders
call it direct.

Because that second method would be easy to code and understand, that
is probably what I would do. A few choice (global) references is sometimes
necessary to simplify a large part of the program. This certainly seems to
be one of those times....

While some may discourage using global variables, and avoid them at all
costs, I am not that strict. It pays off, on occasion, to make a few objects
globally available. To those who think otherwise, I would simply ask them
how they would call DoEvents, if the Application object wasn't available,
or other such common tasks that are included in (what appears to be) globally
available objects....

Do as you see fit. I favor a simple design when it will work well, so in this
case, a global variable seems appropreate for the job....

LFS
 
O

One Handed Man \( OHM - Terry Burns \)

Thanks very much for your help here, it has assisted me greatly.

I am not really trying to build a proper space invaders as you correctly
suggest, just trying to get a handle on threading issues which is something
I have not had to do 'much' of in the past other than one or two cursory
routines which would have tripped the UI.

I think I picked an awkward example unbeknown to me, however, it has served
to illustrate several points to me as far as design consideration is
concerned.

Thanks Again . . .


Best Regards - OHM
--
OHM ( Terry Burns ) * Use the following to email me *

Dim ch() As Char = "ufssz/cvsotAhsfbuTpmvujpotXjui/OFU".ToCharArray()
For i As Int32 = 0 To ch.Length - 1
ch(i) = Convert.ToChar(Convert.ToInt16(ch(i)) - 1)
Next
Process.Start("mailto:" & New String(ch))
 

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

Similar Threads

Why Won't My Thread Abort 5
My Turn - Threading 10
basic threading question 2
Threading 1
Threading and Forms 2
API parameter is events Structure 1
Threading with forms 5
Does this thread code look OK 13

Top