Multithreaded Problem

  • Thread starter Thread starter My name
  • Start date Start date
M

My name

Ok, this *should* have been easy, but I can't get this to work right.

What is happening in the following example is that in the myTest class, the
oThing is nothing after the first thread finishes Here is code sample:

Public Class myClass
private shared WithEvents myObject as myTest
Public Sub ThreadDone handles myObject.IDidIt ....

dim myObject as new myTest
Sub Main()
Dim i as int16 =0
Dim t(5) as thread
For each oThing in myThings
myObject.myThing = oThing
t(i)=new thread(AddressOf myObject.DoThing() )
i=i+1
Next
end sub
end class

Public Class myTest
Public Event IDidIt()
Public Property myThing() As oThing ...

Public Sub DoThing()
if _p.DoTheRealMagic() then
RaiseEvent IDidIt()
end sub
end class

---------------------

What is going wrong here?

TIA -
Larry
 
My name said:
Ok, this *should* have been easy, but I can't get this to work right.

What is happening in the following example is that in the myTest class, the
oThing is nothing after the first thread finishes Here is code sample:

<snip>

Well, for one thing you're only using a single myTest, and constantly
changing the value of oThing - there's nothing to say that the thread
you start will have picked up the value before you move on and change
it to something else.

I strongly suggest you use a myTest object *per thread*.

If that doesn't work, please post a short but complete program which
demonstrates the problem.

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
You don't appear to start the threads - where would that take place?

What is _p?

Where is oThing = Nothing? At what point in the code?

Can you post something that compiles so we can check out what you mean?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Ok, this *should* have been easy, but I can't get this to work right.

What is happening in the following example is that in the myTest class, the
oThing is nothing after the first thread finishes Here is code sample:

Public Class myClass
private shared WithEvents myObject as myTest
Public Sub ThreadDone handles myObject.IDidIt ....

dim myObject as new myTest
Sub Main()
Dim i as int16 =0
Dim t(5) as thread
For each oThing in myThings
myObject.myThing = oThing
t(i)=new thread(AddressOf myObject.DoThing() )
i=i+1
Next
end sub
end class

Public Class myTest
Public Event IDidIt()
Public Property myThing() As oThing ...

Public Sub DoThing()
if _p.DoTheRealMagic() then
RaiseEvent IDidIt()
end sub
end class

---------------------

What is going wrong here?

TIA -
Larry
 
Jon Skeet said:
Well, for one thing you're only using a single myTest, and constantly
changing the value of oThing - there's nothing to say that the thread
you start will have picked up the value before you move on and change
it to something else.

In fact, as Richard pointed out, you don't actually start the threads
in the code you've posted, so the value will *definitely* have changed
before you start the threads!
 
Sorry for the incomplete example before. In this example, it duplicates
the problem. For some reason ThreadDone does not execute either, but the
core problem is in here. What am I missing??

Here's the whole thing:

Imports System
Imports System.Threading
Imports System.Collections

Public Class Class1
Private myThings As New ArrayList
Public Shared WithEvents myObject As myTest
Public Shared Sub ThreadDone() Handles myObject.evIDidIt
Console.WriteLine(String.Format("Thread {0} has completed",
Thread.CurrentThread.Name))
End Sub
Sub Main()

Dim i As Int16
Dim t(5) As Thread
Dim myObject As New myTest

For Each oThing As Thing In myThings
myObject.thing = oThing
t(i) = New Thread(AddressOf myObject.DoThing)
t(i).Name = "Thread " + i.ToString
t(i).Start()
i = i + 1
oThing = Nothing
Next

For n As Int16 = 0 To 5
t(n).Join()
Next


End Sub

Public Sub New()
Dim oThing As Thing
For i As Int16 = 0 To 5
oThing = New Thing(i)
myThings.Add(oThing)
Next
End Sub

End Class

Public Class myTest
Public Event evIDidIt()
Private _thing As Thing

Public Property thing() As Thing
Get
Return _thing
End Get
Set(ByVal Value As Thing)
_thing = Value
End Set
End Property

Public Sub DoThing()
If _thing.DoTheRealMagic() Then
RaiseEvent evIDidIt()
End If
End Sub
End Class

Public Class Thing
Private _id As Int16
Public Sub New()

End Sub
Public Sub New(ByVal id As Int16)
_id = id
End Sub
Public Property Id() As Int16
Get
Return _id
End Get
Set(ByVal Value As Int16)
_id = Value
End Set
End Property

Public Function DoTheRealMagic() As Boolean
Thread.Sleep(1000)
Console.WriteLine(String.Format("RealMagic done for id {0} on
{1}", _id.ToString, Thread.CurrentThread.Name))
Return True
End Function
End Class

------------------------------------------
The output is :
RealMagic done for id 3 on Thread 0
RealMagic done for id 4 on Thread 1
RealMagic done for id 3 on Thread 2
RealMagic done for id 5 on Thread 3
RealMagic done for id 5 on Thread 4
RealMagic done for id 5 on Thread 5
 
So I guess you're expecting to see

RealMagic done for id 0 on Thread 0
RealMagic done for id 1 on Thread 1
RealMagic done for id 2 on Thread 2
RealMagic done for id 3 on Thread 3
RealMagic done for id 4 on Thread 4
RealMagic done for id 5 on Thread 5

This is never going to happen because of what Jon said earlier. By the time DoThing calls _thing.DoTheRealMagic _thing will have been changed by the main thread - thats what you are seeing. You should use a separate Class1 instance per thread.

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Sorry for the incomplete example before. In this example, it duplicates
the problem. For some reason ThreadDone does not execute either, but the
core problem is in here. What am I missing??

Here's the whole thing:
 
I'm not very fluent in VB (rather C# and J#) but it sounds like something is
seriously wrong here.

You are using myObject.thing to pass information between the main thread and
the subthreads but you did not put any synchronization logic to guarantee
that myObject.thing does not change between the time you set it and the time
the thread will read it. Then, it is not surprising that the loop replaces
myObject.thing before the thread picks it up.

Things would go much better if you move the line
Dim myObject as New MyTest
inside the loop, just after the For Each, because then, every thread will
work on a different instance of MyTest.

Bruno.
 
Oh yeah, the reason the HandleEvent wasn't working was because I had w
myObjects defined.

In sub main(), it should read myObject = new myTest instead of the Dim
statement.

Now the code produces the following. Note that the ID stays the same.
Sometimes it does, other times it doesn't. It never matches the thread #
though, which is what I expect.


RealMagic done for id 5 on Thread 0
Thread Thread 0 has completed
RealMagic done for id 5 on Thread 1
Thread Thread 1 has completed
RealMagic done for id 5 on Thread 4
Thread Thread 4 has completed
RealMagic done for id 5 on Thread 5
Thread Thread 5 has completed
RealMagic done for id 5 on Thread 2
Thread Thread 2 has completed
RealMagic done for id 5 on Thread 3
Thread Thread 3 has completed
 
My name said:
Sorry for the incomplete example before. In this example, it duplicates
the problem. For some reason ThreadDone does not execute either, but the
core problem is in here. What am I missing??

Exactly what I said before - you've got a single object, rather than
one object per thread. You're starting the thread and then changing the
value of the property to the next value, so depending on when the
thread actually does its work, it may see the old (correct) value or
the new value.
 
Thanks All. I knew it was something overlooked.

I am guessing that I lose the ability to handle events on the thread
because the WithEvents cannot be used for the local variables, but I can
make this work.

Larry
 
Larry Richardson said:
Thanks All. I knew it was something overlooked.

I am guessing that I lose the ability to handle events on the thread
because the WithEvents cannot be used for the local variables, but I can
make this work.

WithEvents isn't the only way of using event handlers - indeed C#
doesn't even have an equivalent of WithEvents.

Instead, use AddHandler to add a handler to a particular event.
 
Back
Top