Object initialization in C# thread - unexplained behaviour

R

Ricardo Pereira

Hello all,

I have a C# class (in this example, called A) that, in its
constructor, starts a thread with a method of its own. That thread
will be used to continuously check for one of its object's state and
generate classe's A events "Connected" and "Disconnected".

It looks something like this:

"
public class A
{
private AnotherObject an_obj;
private Thread thr;
...

public event System.EventHandler Connected;
public event System.EventHandler Disconnected;

public A()
{
thr = new Thread(new ThreadStart(this.DoThreadWork));
thr.Start();
while (!thr.IsAlive);
thr.IsBackground = true;
}

private void DoThreadWork()
{
an_obj = new AnotherObject();

while(true)
{
if (an_obj.IsPresent())
if (Connected != null)
Connected(this, EventArgs.Empty);
else
if (Disconnected != null)
Disconnected(this, EventArgs.Empty);
}
}

public void DoSomethingX()
{
an_obj.CallXWork();
}

public int DoSomethingY()
{
return an_obj.CallYWork();
}
}
"

and a form that uses the previous class:

"
public class Form1: System.Windows.Forms.Form
{
private A objA;
...

public Form1()
{
objA = new SmartcardEVController();

objA.Connected += new EventHandler(objA_Connected);
objA.Disconnected += new EventHandler(objA_Disconnected);
}

private void objA_Connected(object sender, EventArgs e)
{
objA.DoSomethingX();
}

private void objA_Disconnected(object sender, EventArgs e)
{
int i = objA.DoSomethingY();
MessageBox.Show("Value: " + i);
}

private void button1_Click(object sender, System.EventArgs e)
{
objA.DoSomethingX();
MessageBox.Show("Done");
}
}
"


The problem is that although every call made to object "objA", inside
the "objA_Connected" or "objA_Disconnected" captured event works
perfectly fine, when a method is called on "objA" anywhere else it
just blocks the program execution. In this example, when button1 is
clicked, the instruction "MessageBox.Show("Done");" won't get called
and the program (Form1) will stop responding.

By the way, class AnotherObj is a .NET wrapper for a C dll that, in
turn, is a JNI wrapper for a Java class. All Java methods are
"synchronized".

I thought that this could be a problem of the Java object but the fact
is that the cycle inside the thread keeps on executing when calls are
made inside "objA_Connected" or "objA_Disconnected" and those calls
execute successfully, no matter how many calls are made to object
"objA".
A strange thing that happens is that the call "objA.DoSomethingX();"
inside the click event makes the corresponding Java method start
executing (using log utilities in Java, I can check that the method
began execution but then stopped for no apparent reason).

The only thing I can now think of is that the thread that is spawned
in the A class has some kind of own memory space that the object that
was initialized inside the thread ("an_obj") can't be safely used
outside the thread. Being the thread that generates the events
"Connected" and "Disconnected", that could explain that calls to
object "objA", inside "objA_Connected" and "objA_Disconnected",
executed well. But that's only an hipothetical thought.

p.s.: I also tried initializing object "an_obj" outside the thread, in
classe's A contructor, but that way the call "an_obj.IsPresent())"
would also block in the C dll (that calls JNI code) for no apparent
reason.

If anyone could give me an explanation of why this is happening and
what I can do to avoid it, I would be grateful, as I can't figure it
out just by myself.

Thank you very much,
Ricardo Pereira
 
N

Nicholas Paldino [.NET/C# MVP]

Ricardo,

To me, it seems that the problem is arising from the fact that your
event is coming in on a separate thread, which then tries to access windows
elements outside of the thread that they were created in. When you call the
static Show method on the MessageBox class, it is not on the main UI thread.
In order to marshal the call to the correct thread, you need to call the
Invoke method on a control that is created on the UI thread (your form would
be fine). You then pass a delegate pointing to the method to be called on
the UI thread, along with any parameters that are needed.

Hope this helps.
 
J

Jon Skeet [C# MVP]

If anyone could give me an explanation of why this is happening and
what I can do to avoid it, I would be grateful, as I can't figure it
out just by myself.

Could you 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.

Cut out all the Java stuff and just give some bare-bones .NET-only code
which shows the problem.

By the way, the line

while (!thr.IsAlive) ;

is a pretty nasty way of waiting for the thread to start - a
Thread.Sleep call in the loop would at least stop it from being *quite*
such a tight loop.

(I'm not sure why you're waiting for it to start before making it a
background thread anyway, to be honest.)

Similarly, I hope an_obj.IsPresent() is waiting or sleeping or
something similar, otherwise you've got another potentially tight loop
there - never a good idea.
 
S

Scott Allen

Hi Ricardo:

The following line of code in class A's constructor is putting the
calling thread into an infinite loop:

while (!thr.IsAlive);

Because the thread you are creating (thr) is also in an infinite
while(true) loop.

The thread calling the constructor on A is the user interface thread,
you won't see the form refresh or react to events until the thread is
free to process those events.

Polling the outside object to generate the connect and disconnect
events will in this fashion will be very expensive. Are there any
events on the AnotherObject object you can subscribe to? It's hard to
tell what you need to accomplish but somehow I think invoking
CallXWork infinitely is not what you want to do.
 
J

Jon Skeet [C# MVP]

Scott Allen said:
The following line of code in class A's constructor is putting the
calling thread into an infinite loop:

while (!thr.IsAlive);

Because the thread you are creating (thr) is also in an infinite
while(true) loop.

Nope - while (!thr.IsAlive); is just waiting for the thread to actually
start. It's not a good idea, but it's not actually an infinite loop.
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Hi Ricardo,

I IMHO the probelm is not in the that class. The probem is in the C dll or
Java code.
I can't say why it doesn't work, but I dare to say the problem is not in
this code.

For example AnotherObject class can be thread sensitive just like Control
classes are. Even it can use windows controls itself.

In this case the an_obj is created inside the new worker thread. When you
call from within the event handlers you call the method in the context of
the thread created the object.
When call it form the button click you call the an_obj's method not from the
thread created the object. If an_obj uses UI contrlos it may block.
Try to move
an_obj = new AnotherObject();
from DoThreadWork to the constructor. See if it behaves in the same way.
As a matter of fact threads do have local thread storage, but as far as I
can see this code doesn't use it.
 
S

Stoitcho Goutsev \(100\) [C# MVP]

Hi Nicholas,

AFAIK you can call MessageBox.Show. from any thread.

--

Stoitcho Goutsev (100) [C# MVP]


Nicholas Paldino said:
Ricardo,

To me, it seems that the problem is arising from the fact that your
event is coming in on a separate thread, which then tries to access windows
elements outside of the thread that they were created in. When you call the
static Show method on the MessageBox class, it is not on the main UI thread.
In order to marshal the call to the correct thread, you need to call the
Invoke method on a control that is created on the UI thread (your form would
be fine). You then pass a delegate pointing to the method to be called on
the UI thread, along with any parameters that are needed.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Ricardo Pereira said:
Hello all,

I have a C# class (in this example, called A) that, in its
constructor, starts a thread with a method of its own. That thread
will be used to continuously check for one of its object's state and
generate classe's A events "Connected" and "Disconnected".

It looks something like this:

"
public class A
{
private AnotherObject an_obj;
private Thread thr;
...

public event System.EventHandler Connected;
public event System.EventHandler Disconnected;

public A()
{
thr = new Thread(new ThreadStart(this.DoThreadWork));
thr.Start();
while (!thr.IsAlive);
thr.IsBackground = true;
}

private void DoThreadWork()
{
an_obj = new AnotherObject();

while(true)
{
if (an_obj.IsPresent())
if (Connected != null)
Connected(this, EventArgs.Empty);
else
if (Disconnected != null)
Disconnected(this, EventArgs.Empty);
}
}

public void DoSomethingX()
{
an_obj.CallXWork();
}

public int DoSomethingY()
{
return an_obj.CallYWork();
}
}
"

and a form that uses the previous class:

"
public class Form1: System.Windows.Forms.Form
{
private A objA;
...

public Form1()
{
objA = new SmartcardEVController();

objA.Connected += new EventHandler(objA_Connected);
objA.Disconnected += new EventHandler(objA_Disconnected);
}

private void objA_Connected(object sender, EventArgs e)
{
objA.DoSomethingX();
}

private void objA_Disconnected(object sender, EventArgs e)
{
int i = objA.DoSomethingY();
MessageBox.Show("Value: " + i);
}

private void button1_Click(object sender, System.EventArgs e)
{
objA.DoSomethingX();
MessageBox.Show("Done");
}
}
"


The problem is that although every call made to object "objA", inside
the "objA_Connected" or "objA_Disconnected" captured event works
perfectly fine, when a method is called on "objA" anywhere else it
just blocks the program execution. In this example, when button1 is
clicked, the instruction "MessageBox.Show("Done");" won't get called
and the program (Form1) will stop responding.

By the way, class AnotherObj is a .NET wrapper for a C dll that, in
turn, is a JNI wrapper for a Java class. All Java methods are
"synchronized".

I thought that this could be a problem of the Java object but the fact
is that the cycle inside the thread keeps on executing when calls are
made inside "objA_Connected" or "objA_Disconnected" and those calls
execute successfully, no matter how many calls are made to object
"objA".
A strange thing that happens is that the call "objA.DoSomethingX();"
inside the click event makes the corresponding Java method start
executing (using log utilities in Java, I can check that the method
began execution but then stopped for no apparent reason).

The only thing I can now think of is that the thread that is spawned
in the A class has some kind of own memory space that the object that
was initialized inside the thread ("an_obj") can't be safely used
outside the thread. Being the thread that generates the events
"Connected" and "Disconnected", that could explain that calls to
object "objA", inside "objA_Connected" and "objA_Disconnected",
executed well. But that's only an hipothetical thought.

p.s.: I also tried initializing object "an_obj" outside the thread, in
classe's A contructor, but that way the call "an_obj.IsPresent())"
would also block in the C dll (that calls JNI code) for no apparent
reason.

If anyone could give me an explanation of why this is happening and
what I can do to avoid it, I would be grateful, as I can't figure it
out just by myself.

Thank you very much,
Ricardo Pereira
 
S

Scott Allen

Oops, missed the negation operator.

Nope - while (!thr.IsAlive); is just waiting for the thread to actually
start. It's not a good idea, but it's not actually an infinite loop.
 
R

Ricardo Pereira

Hi and thank you all for your tips.

It seems that the problem did have something to do with the fact that
some of the code from the DLL (the one that calls JNI code) was being
called from the spawned thread and some other was being called from
the main thread, and JNI blocked somewhere (probably looking for some
resources that were only availabe in the initial thread).

This got resolved by implementing a COM object instead of the regular
DLL, for the reason that this COM object can end up running everything
in a single thread, which solves the problem.


Thanks again for everyone.
Ricardo Pereira
 
T

TT \(Tom Tempelaere\)

Ricardo Pereira said:
Hello all,

I have a C# class (in this example, called A) that, in its
constructor, starts a thread with a method of its own. That thread
will be used to continuously check for one of its object's state and
generate classe's A events "Connected" and "Disconnected".

It looks something like this: [...]
public A()
{
thr = new Thread(new ThreadStart(this.DoThreadWork));
thr.Start();
while (!thr.IsAlive);
thr.IsBackground = true;
}
[...]

It is better not to poll like you do in the while loop. It is better to use
a ManualResetEvent object and wait (WaitHandle.WaitOne) on it for the thread
to come alive. Let the thread you start signal the event when it starts
(ManualResetEvent.Set).

Cheers,
 
A

AlexS

I agree, while loop is unnecessary. IsBackground = true could be done from
inside DoThreadWork method. Which will be a bit simpler than signalling.

HTH
Alex

TT (Tom Tempelaere) said:
Ricardo Pereira said:
Hello all,

I have a C# class (in this example, called A) that, in its
constructor, starts a thread with a method of its own. That thread
will be used to continuously check for one of its object's state and
generate classe's A events "Connected" and "Disconnected".

It looks something like this: [...]
public A()
{
thr = new Thread(new ThreadStart(this.DoThreadWork));
thr.Start();
while (!thr.IsAlive);
thr.IsBackground = true;
}
[...]

It is better not to poll like you do in the while loop. It is better to use
a ManualResetEvent object and wait (WaitHandle.WaitOne) on it for the thread
to come alive. Let the thread you start signal the event when it starts
(ManualResetEvent.Set).

Cheers,
 
J

Jon Skeet [C# MVP]

AlexS said:
I agree, while loop is unnecessary. IsBackground = true could be done from
inside DoThreadWork method. Which will be a bit simpler than signalling.

Or it could just be done before the thread is started, which is even
simpler and more logical (from my point of view) as it makes sense to
me to set up everything to do with the thread (name, background,
priority etc) before starting it.
 
R

Ricardo Pereira

That, you are absolutely correct.
I had already had that changed.

Thanks again,
Ricardo Pereira
 

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