Reputation: 11
I am attempting to use SetEvent
and WaitForMultipleObjects
so I wrote a couple of functions that I wanted to synchronize using Events. I want the first function to execute, and then signal the second function to execute, which in turn signals the first function to execute again etc.
Two events were created, one initialized to a signaled state, the other unsignaled. The only way I can get the execution to flow as expected is when putting the each thread to sleep for 10 ms. I read about some caveats about using SetEvent: http://cboard.cprogramming.com/windows-programming/100818-setevent-resetevent-3.html
My question is must I put my threads to sleep because these function calls require extra time to actually signal the events? When debugging sometimes an event that is set still remains unsignalled. I verify this using process explorer. My code basically looks like this:
in the main:
//1. FinCalcpidUpdatestruct << initialize to unsignalled
//2. FinUpdatestructCalcpid << initialize to signalled
FinCalcpidUpdatestruct = CreateEvent (NULL, FALSE, FALSE, TEXT("FinCalcpidUpdatestruct"));
FinUpdatestructCalcpid = CreateEvent (NULL, FALSE, TRUE, TEXT ("FinUpdatestructCalcpid"));
void function1()
{
int n;
int noGoCode;
n=0;
noGoCode = 0;
while(1)
{
//Sleep(10);
noGoCode = WaitForSingleObject (FinCalcpidUpdatestruct, INFINITE);
if (noGoCode == WAIT_OBJECT_0) {
//wait for FinCalcpidUpdatestruct to be signalled
BufferOut[n] = pid_data_array -> output;
//signal FinUpdatestructCalcpid
if(!SetEvent (FinUpdatestructCalcpid))
printf("Couldn't set the event FinUpdatestructCalcpid\n");
else{
printf("FinUpdatestructCalcpid event set\n");
Sleep(10);
}
}
else
printf("error\n");
}
}
void function2()
{
int nGoCode = 0;
while(1)
{
//wait for FinUpdatestructCalcpid to be signalled
// Sleep(10);
nGoCode = WaitForSingleObject (FinUpdatestructCalcpid, INFINITE);
if (nGoCode == WAIT_OBJECT_0) {
if(!SetEvent (FinCalcpidUpdatestruct))
printf("Couldn't set the event FinCalcpidUpdatestruct\n");
else{
printf("FinCalcpidUpdatestruct event set\n");
Sleep(10);
}
}
else
printf("error\n");
}//end while(1)
If the sleep is not used then sometimes the same function will run through the while loop a couple of times instead of ping ponging back and forth between the two functions. Any ideas?
Upvotes: 0
Views: 2142
Reputation: 69632
Let me cut your code short for brevity first:
FinCalcpidUpdatestruct = CreateEvent (NULL, FALSE, FALSE, TEXT("FinCalcpidUpdatestruct"));
FinUpdatestructCalcpid = CreateEvent (NULL, FALSE, TRUE, TEXT ("FinUpdatestructCalcpid"));
void function1()
{
while(1)
{
WaitForSingleObject (FinCalcpidUpdatestruct, INFINITE);
// Do Something
SetEvent (FinUpdatestructCalcpid);
printf(...);
Sleep(10);
}
}
void function2()
{
while(1)
{
nGoCode = WaitForSingleObject (FinUpdatestructCalcpid, INFINITE);
SetEvent (FinCalcpidUpdatestruct);
printf(...); // **A**
Sleep(10);
}
}
At basically any point of execution the control might be taken away from thread and given to another. Now suppose that function2
already set the event and is about to print output around **A**
in code. Before the output is printed, the control is taken away and given to function1
. The last printed output is already from function1
and its wait event is set, so it falls through and prints its stuff again.
When this happens, your output is once in a while:
function1
function2
function1
function2
function1
// When the situation **A** above happens:
function1
function2
function2
function1
// And we move on as usual further
function2
function1
function2
Set your events when you are done, that is after printf
, and you will be fine.
Upvotes: 1
Reputation: 7271
You can fix the problem by adding a printf
above the SetEvent
call on each function.
The problem is that you are setting the event and then performing some output.
In function2
the printf
occurs after the SetEvent
:
// Add a printf call here to see sensible output.
if(!SetEvent (FinUpdatestructCalcpid))
printf("Couldn't set the event FinUpdatestructCalcpid\n");
else{
// Thread is pre-empted by kernel here. This is not executed immediately
printf("FinUpdatestructCalcpid event set\n");
}
The kernel preempts the thread running function2
so the FinUpdatestructCalcpid
event has now been set, without the corresponding printf
that you're expecting.
The thread running function1
is then executed and sets the FinUpdatestructCalcpid
event. The thread running function2
is now allowed to execute and continues from where it left off. It runs the printf
and because the FinUpdatestructCalcpid
event has been set it immediately runs again.
The Sleep()
calls you're using help to make this race condition unlikely, but do not eliminate it.
Upvotes: 3
Reputation: 63461
Here's what I think...
You don't output any status until you have already set the event. At that point, execution could switch to the other thread before you output anything. If that thread runs first, then it might look as if one thread's loop has run through a second time -- a ping with out a pong...
But if you were to increment a global counter in between receiving a signal and setting an event, then save that counter's value to a local variable, you would probably find that one thread's count is always odd and the other's is always even (which is the behaviour you want), even if the output is not quite in order.
Upvotes: 0