Threading / Event issue...

  • Thread starter Thread starter Brian H
  • Start date Start date
B

Brian H

Hi all,

I've spent a couple of hours to observe this behavior... In my app, I have
an option that, if selected, spawns a new thread, and waits for the top of
the hour to play a sound. I wait for this event with something like:

Result = WaitForSingleObject(ExitEvent, WaitMilliseconds)

If you disable this option -- or if the app is exited -- I raise the exit
event (courtesy of OpenNetCF SetEvent) to exit the thread. This works fine.

But I've since added a bunch of options that may change the fequency of when
this sound plays. For example, perhaps it will play every 10 minutes,
instead of the top of the hour. So when this property is set based on user
input, this first thing I always do is force the thread to exit by pulsing
the event:

OpenNETCF.Win32.Core.SetEvent(ExitEvent)

The property set then evaluates the current state of various options, then
respawns the thread. The idea here is that, if the app is waiting until the
top of the hour to do something, but now I want it to go off in 5 minutes, I
want to abort, then reset the thread.

The crux of the problem is that if I pulse the ExitEvent, then immediately
spawn the new thread, I'm seeing inconsistent behavior in the thread exiting
before it gets respawned. So more or less, I've done something like this:

OpenNETCF.Win32.Core.SetEvent(ExitEvent)
Thread.Sleep(250)

If Value = true or (other evaluations here) Then
WaitThread = New Thread(AddressOf WaitForNextChime)
WaitThread.Start()
End If

By adding the thread.sleep, I'm now seeing the thread is always exiting
before getting respawned. 250 may be too high a value, but I'm looking for
feedback on this. Without the thread.sleep, sometimes the thread exits
first, sometimes it doesn't.

Thanks for any feedback!
Brian
 
I believe the proper thing to do would be upon setting the event to
WaitForSingleObject on the hThread to make sure it ended
 
Alex,

Could you provide more info? I believe that's what I'm doing. For example,
in my code (most logic snipped out, constants/declarations exist, just not
copied below):

Private Sub WaitForNextChime()

ExitEvent = CreateEvent(IntPtr.Zero, 0, 0, "ChimeExit")

While 1
'various logic here to determine the WaitMilliseconds
Result = WaitForSingleObject(ExitEvent, WaitMilliseconds)
If Result = WAIT_TIMEOUT Then
' code to play chime

Else
' Exit the thread
'Write to a log file for debugging.
Exit While
End If
Loop
End sub

To start my thread, I do this:
ChimeThread = New Thread(AddressOf WaitForNextChime)
ChimeThread.Start()

Now, if at any time, I do this:
OpenNETCF.Win32.Core.SetEvent(ExitEvent)
....all is good. My thread exits.

If I do this (other logic snipped out, but basically these commands happen
in my property set):
OpenNETCF.Win32.Core.SetEvent(ExitEvent)
ChimeThread = New Thread(AddressOf WaitForNextChime)
ChimeThread.Start()
....all is not so good. Sometimes, I see the thread exiting, other times it
does not. By adding a thread.sleep between the SetEvent and thread
spawning, it works fine...

Again, the reason I'm exiting the thread, then immediately respawning is
because the wait time has been adjusted. I could add a global flag that
differentiates between the app exiting and just a "recycle," and not
actually exit the thread if we're just changing the timeout. But that's not
the point :)

Thanks for your help,
Brian
 
Yes; actually I could launch into another set of questions.

I'm not quite sure what the difference is, other than the obvious.
Originally I had it as a manual reset. The thread, when respawned, would
always immediately exit. I then realized the second parameter was
auto/manual reset, so I set it to auto reset (not quite sure how to reset
the event manually).

Ah, so ... do you think the thread is getting spawned and, the event
recreated before the WaitForSingleObject received the exit event?

Thanks for your help,
Brian
 
I was considering whether the event might be set and reset before the thread
gets to where it's waiting. It was not clear from your code how the event
handle was being sent from main thread to wait thread. You might consider
creating the event once, in the main thread, and passing it to the wait
thread as part of the constructor. This should work fine and will assure
that the CreateEvent() call in the main thread determines the parameters of
the event (it will be *the* place where the event is created).

You should also *wait for the chime thread to exit* in the main thread
before firing another instance for the new time-out. That is, if you want
to immediately start a new thread, you need to do something like this:

SetEvent( stopThreadEvent );
WaitForSingleObject( threadHandle ); // Wait for the current thread to
exit.
CloseHandle( threadHandle ); // It will leak, if you don't do
this.
CreateThread( new chime thread ); // Start thread with the new
time-out.

If I were writing this code in C, I'd add some debug output messages to the
thread and to the main thread to see what's going on.

Another thing to think about is the possibility of having the chime thread
*always* running (it only exits when the application exits). When there's a
change in the settings, fire a *different* event to signal the thread to
recalculate the time-out and have it use WaitForMultipleObjects() rather
than the single object wait. I do something like this in the display driver
for our devices to turn off the backlight after a period of inactivity. One
event signals a Control Panel setting change, one signals a change in the
power state, and, of course, time-out signals that it's time to turn the
backlight off.

Paul T.
 
Great info, Paul, many thanks.

Very likely this was leaking all along, as I never did a CloseHandle. I'll
make sure I'm doing that.

I'd like to tinker with the WaitForMultipleObjects() and leave the thread as
always running. I have some questions, though -- this is just pseudocode
here but it looks like the WaitForMultipleObjects takes an intptr array. So
let's say I've got:

ChimeExitEvent = CreateEvent(IntPtr.Zero, 0, 0, "ChimeExit") ' Only
fired when the app is exiting
ChimeChangeEvent = CreateEvent(IntPtr.Zero, 0, 0, "ChimeChange") ' Fired
when we need to exit the wait and recalc

When you get the result back, how would you evaluate the result to determine
which event triggered it? Meaning, I know when the TIMEOUT is reached, but
how to know which event was fired to cause the event to exit?

(somewhat pseudo, I'm constantly switching between VB and C#:)
Result = WaitForMultipleObjects(new inptr[1] {ChimeExitEvent,
ChimeChangeEvent}, 0, WaitMilliseconds) ;

If Result = WAIT_TIMEOUT Then
' timeout, do stuff
Else
' ?? which event was fired?
end if

Many thanks again,
Brian
 
WaitForMultipleObjects() takes an array of handles, yes. I think something
like:

IntPtr[] handles = new IntPtr[ 2 ];
handles[ 0 ] = < handle 1 >;
handles[ 1 ] = < handle 2 >;

int result = WaitForMultipleObjects( handles, 0, timeout );

if ( result == 0 ) // WAIT_OBJECT_0
{
// Element 0 in the handle array caused the wait to end.
}
else if ( result == 1 ) // WAIT_OBJECT_0 + 1
{
// Element 1 in the handle array caused the wait to end.
}
else if ( result == 258 ) // WAIT_TIMEOUT
{
// Time-out
}
else
{
// Some type of error.
}

is what you want.

Paul T.

Brian H said:
Great info, Paul, many thanks.

Very likely this was leaking all along, as I never did a CloseHandle. I'll
make sure I'm doing that.

I'd like to tinker with the WaitForMultipleObjects() and leave the thread as
always running. I have some questions, though -- this is just pseudocode
here but it looks like the WaitForMultipleObjects takes an intptr array. So
let's say I've got:

ChimeExitEvent = CreateEvent(IntPtr.Zero, 0, 0, "ChimeExit") ' Only
fired when the app is exiting
ChimeChangeEvent = CreateEvent(IntPtr.Zero, 0, 0, "ChimeChange") ' Fired
when we need to exit the wait and recalc

When you get the result back, how would you evaluate the result to determine
which event triggered it? Meaning, I know when the TIMEOUT is reached, but
how to know which event was fired to cause the event to exit?

(somewhat pseudo, I'm constantly switching between VB and C#:)
Result = WaitForMultipleObjects(new inptr[1] {ChimeExitEvent,
ChimeChangeEvent}, 0, WaitMilliseconds) ;

If Result = WAIT_TIMEOUT Then
' timeout, do stuff
Else
' ?? which event was fired?
end if

Many thanks again,
Brian


Paul G. Tobey said:
I was considering whether the event might be set and reset before the thread
gets to where it's waiting. It was not clear from your code how the event
handle was being sent from main thread to wait thread. You might consider
creating the event once, in the main thread, and passing it to the wait
thread as part of the constructor. This should work fine and will assure
that the CreateEvent() call in the main thread determines the parameters of
the event (it will be *the* place where the event is created).

You should also *wait for the chime thread to exit* in the main thread
before firing another instance for the new time-out. That is, if you want
to immediately start a new thread, you need to do something like this:

SetEvent( stopThreadEvent );
WaitForSingleObject( threadHandle ); // Wait for the current thread to
exit.
CloseHandle( threadHandle ); // It will leak, if you
don't
do
this.
CreateThread( new chime thread ); // Start thread with the new
time-out.

If I were writing this code in C, I'd add some debug output messages to the
thread and to the main thread to see what's going on.

Another thing to think about is the possibility of having the chime thread
*always* running (it only exits when the application exits). When
there's
a
change in the settings, fire a *different* event to signal the thread to
recalculate the time-out and have it use WaitForMultipleObjects() rather
than the single object wait. I do something like this in the display driver
for our devices to turn off the backlight after a period of inactivity. One
event signals a Control Panel setting change, one signals a change in the
power state, and, of course, time-out signals that it's time to turn the
backlight off.

Paul T.

respawning flag
that for
the raise
the
exit
in
5 something
like
 
Many thanks!

Paul G. Tobey said:
WaitForMultipleObjects() takes an array of handles, yes. I think something
like:

IntPtr[] handles = new IntPtr[ 2 ];
handles[ 0 ] = < handle 1 >;
handles[ 1 ] = < handle 2 >;

int result = WaitForMultipleObjects( handles, 0, timeout );

if ( result == 0 ) // WAIT_OBJECT_0
{
// Element 0 in the handle array caused the wait to end.
}
else if ( result == 1 ) // WAIT_OBJECT_0 + 1
{
// Element 1 in the handle array caused the wait to end.
}
else if ( result == 258 ) // WAIT_TIMEOUT
{
// Time-out
}
else
{
// Some type of error.
}

is what you want.

Paul T.

Brian H said:
Great info, Paul, many thanks.

Very likely this was leaking all along, as I never did a CloseHandle. I'll
make sure I'm doing that.

I'd like to tinker with the WaitForMultipleObjects() and leave the
thread
as
always running. I have some questions, though -- this is just pseudocode
here but it looks like the WaitForMultipleObjects takes an intptr array. So
let's say I've got:

ChimeExitEvent = CreateEvent(IntPtr.Zero, 0, 0, "ChimeExit") ' Only
fired when the app is exiting
ChimeChangeEvent = CreateEvent(IntPtr.Zero, 0, 0, "ChimeChange") ' Fired
when we need to exit the wait and recalc

When you get the result back, how would you evaluate the result to determine
which event triggered it? Meaning, I know when the TIMEOUT is reached, but
how to know which event was fired to cause the event to exit?

(somewhat pseudo, I'm constantly switching between VB and C#:)
Result = WaitForMultipleObjects(new inptr[1] {ChimeExitEvent,
ChimeChangeEvent}, 0, WaitMilliseconds) ;

If Result = WAIT_TIMEOUT Then
' timeout, do stuff
Else
' ?? which event was fired?
end if

Many thanks again,
Brian


Paul G. Tobey said:
I was considering whether the event might be set and reset before the thread
gets to where it's waiting. It was not clear from your code how the event
handle was being sent from main thread to wait thread. You might consider
creating the event once, in the main thread, and passing it to the wait
thread as part of the constructor. This should work fine and will assure
that the CreateEvent() call in the main thread determines the
parameters
of
the event (it will be *the* place where the event is created).

You should also *wait for the chime thread to exit* in the main thread
before firing another instance for the new time-out. That is, if you want
to immediately start a new thread, you need to do something like this:

SetEvent( stopThreadEvent );
WaitForSingleObject( threadHandle ); // Wait for the current thread to
exit.
CloseHandle( threadHandle ); // It will leak, if you
don't
do
this.
CreateThread( new chime thread ); // Start thread with the new
time-out.

If I were writing this code in C, I'd add some debug output messages
to
the
thread and to the main thread to see what's going on.

Another thing to think about is the possibility of having the chime thread
*always* running (it only exits when the application exits). When
there's
a
change in the settings, fire a *different* event to signal the thread to
recalculate the time-out and have it use WaitForMultipleObjects() rather
than the single object wait. I do something like this in the display driver
for our devices to turn off the backlight after a period of
inactivity.
One
event signals a Control Panel setting change, one signals a change in the
power state, and, of course, time-out signals that it's time to turn the
backlight off.

Paul T.

Yes; actually I could launch into another set of questions.

I'm not quite sure what the difference is, other than the obvious.
Originally I had it as a manual reset. The thread, when respawned, would
always immediately exit. I then realized the second parameter was
auto/manual reset, so I set it to auto reset (not quite sure how to reset
the event manually).

Ah, so ... do you think the thread is getting spawned and, the event
recreated before the WaitForSingleObject received the exit event?

Thanks for your help,
Brian


message Is the event maybe an auto-, rather than manual-reset, event?

Paul T.

Alex,

Could you provide more info? I believe that's what I'm doing. For
example,
in my code (most logic snipped out, constants/declarations
exist,
just
not
copied below):

Private Sub WaitForNextChime()

ExitEvent = CreateEvent(IntPtr.Zero, 0, 0, "ChimeExit")

While 1
'various logic here to determine the WaitMilliseconds
Result = WaitForSingleObject(ExitEvent, WaitMilliseconds)
If Result = WAIT_TIMEOUT Then
' code to play chime

Else
' Exit the thread
'Write to a log file for debugging.
Exit While
End If
Loop
End sub

To start my thread, I do this:
ChimeThread = New Thread(AddressOf WaitForNextChime)
ChimeThread.Start()

Now, if at any time, I do this:
OpenNETCF.Win32.Core.SetEvent(ExitEvent)
...all is good. My thread exits.

If I do this (other logic snipped out, but basically these commands
happen
in my property set):
OpenNETCF.Win32.Core.SetEvent(ExitEvent)
ChimeThread = New Thread(AddressOf WaitForNextChime)
ChimeThread.Start()
...all is not so good. Sometimes, I see the thread exiting, other
times
it
does not. By adding a thread.sleep between the SetEvent and thread
spawning, it works fine...

Again, the reason I'm exiting the thread, then immediately respawning
is
because the wait time has been adjusted. I could add a global flag
that
differentiates between the app exiting and just a "recycle," and not
actually exit the thread if we're just changing the timeout. But
that's
not
the point :)

Thanks for your help,
Brian


I believe the proper thing to do would be upon setting the
event
to
WaitForSingleObject on the hThread to make sure it ended

--
Alex Feinman
---
Visit http://www.opennetcf.org
Hi all,

I've spent a couple of hours to observe this behavior... In my
app,
I
have
an option that, if selected, spawns a new thread, and waits for
the
top
of
the hour to play a sound. I wait for this event with something
like:

Result = WaitForSingleObject(ExitEvent, WaitMilliseconds)

If you disable this option -- or if the app is exited -- I raise
the
exit
event (courtesy of OpenNetCF SetEvent) to exit the thread. This
works
fine.

But I've since added a bunch of options that may change the
fequency
of
when
this sound plays. For example, perhaps it will play every 10
minutes,
instead of the top of the hour. So when this property is set
based
on
user
input, this first thing I always do is force the thread to
exit
by
pulsing
the event:

OpenNETCF.Win32.Core.SetEvent(ExitEvent)

The property set then evaluates the current state of various
options,
then
respawns the thread. The idea here is that, if the app is waiting
until
the
top of the hour to do something, but now I want it to go off
in
5
minutes,
I
want to abort, then reset the thread.

The crux of the problem is that if I pulse the ExitEvent, then
immediately
spawn the new thread, I'm seeing inconsistent behavior in the
thread
exiting
before it gets respawned. So more or less, I've done something
like
this:

OpenNETCF.Win32.Core.SetEvent(ExitEvent)
Thread.Sleep(250)

If Value = true or (other evaluations here) Then
WaitThread = New Thread(AddressOf WaitForNextChime)
WaitThread.Start()
End If

By adding the thread.sleep, I'm now seeing the thread is always
exiting
before getting respawned. 250 may be too high a value, but I'm
looking
for
feedback on this. Without the thread.sleep, sometimes the thread
exits
first, sometimes it doesn't.

Thanks for any feedback!
Brian
 
Back
Top