SetEvent和WaitForMultipleObjects的不可预测行为
我试图使用SetEvent和WaitForMultipleObjects的不可预测行为,c,winapi,synchronization,C,Winapi,Synchronization,我试图使用SetEvent和WaitForMultipleObjects因此我编写了两个函数,希望使用事件同步这些函数。我希望第一个函数执行,然后向第二个函数发出执行信号,这反过来又向第一个函数发出再次执行的信号,等等 创建了两个事件,一个初始化为有信号状态,另一个为无信号状态。我能让执行按预期进行的唯一方法是将每个线程休眠10毫秒。我阅读了有关使用SetEvent的一些注意事项: 我的问题是,我必须让线程休眠,因为这些函数调用需要额外的时间来实际发出事件信号?调试时,有时设置的事件仍保持未调
SetEvent
和WaitForMultipleObjects
因此我编写了两个函数,希望使用事件同步这些函数。我希望第一个函数执行,然后向第二个函数发出执行信号,这反过来又向第一个函数发出再次执行的信号,等等
创建了两个事件,一个初始化为有信号状态,另一个为无信号状态。我能让执行按预期进行的唯一方法是将每个线程休眠10毫秒。我阅读了有关使用SetEvent的一些注意事项:
我的问题是,我必须让线程休眠,因为这些函数调用需要额外的时间来实际发出事件信号?调试时,有时设置的事件仍保持未调用状态。我使用process explorer对此进行验证。我的代码基本上如下所示:
大体上:
//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)
//1。FinCalcpidUpdatestruct以下是我的想法
在设置事件之前,不会输出任何状态。此时,执行可以在输出任何内容之前切换到另一个线程。如果该线程先运行,那么它可能看起来就像一个线程的循环已经运行了第二次--一个没有乒乓球的ping
但是如果在接收信号和设置事件之间增加一个全局计数器,然后将该计数器的值保存到一个局部变量,您可能会发现一个线程的计数总是奇数,而另一个线程的计数总是偶数(这是您想要的行为),即使输出不是很有序。我想
在设置事件之前,不会输出任何状态。此时,执行可以在输出任何内容之前切换到另一个线程。如果该线程先运行,那么它可能看起来就像一个线程的循环已经运行了第二次--一个没有乒乓球的ping
但是如果在接收信号和设置事件之间增加一个全局计数器,然后将该计数器的值保存到一个局部变量,您可能会发现一个线程的计数总是奇数,而另一个线程的计数总是偶数(这是您想要的行为),即使输出不是很有序。您也可以通过在每个函数的SetEvent
调用上方添加printf
来解决问题
问题是您正在设置事件,然后执行一些输出
在function2
中,printf
发生在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");
}
内核支持运行function2
的线程,因此FinUpdatestructCalcpid
事件现在已设置,而没有您期望的相应printf
然后执行运行function1
的线程,并设置FinUpdatestructCalcpid
事件。运行function2
的线程现在可以执行,并从停止的位置继续执行。它运行printf
,由于设置了FinUpdatestructCalcpid
事件,因此它立即再次运行
Sleep()
调用您正在使用的帮助,使此竞态条件不太可能发生,但不要消除它。您可以通过在每个函数的SetEvent
调用上方添加printf
来解决此问题
问题是您正在设置事件,然后执行一些输出
在function2
中,printf
发生在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");
}
内核支持运行function2
的线程,因此FinUpdatestructCalcpid
事件现在已设置,而没有您期望的相应printf
然后执行运行function1
的线程,并设置FinUpdatestructCalcpid
事件。运行function2
的线程现在可以执行,并从停止的位置继续执行。它运行printf
,由于设置了FinUpdatestructCalcpid
事件,因此它立即再次运行
Sleep()
调用您正在使用的帮助,以使此竞态条件不太可能发生,但不要消除它。为了简洁起见,首先让我将代码缩短:
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);
}
}
基本上,在执行的任何一点上,该控件都可以从线程中移除,并交给另一个线程。现在假设function2
已经设置了事件,并且即将在代码中打印**A**
的输出。在打印输出之前,控件被取下并交给功能1
。最后一次打印的输出已经来自function1
,并且它的等待事件已设置,因此它将失败并再次打印其内容
发生这种情况时,您的输出会偶尔出现一次:
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
完成后,即在printf
之后设置事件,您会没事的。为了简洁起见,让我先把代码缩短:
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);
}
}
基本上,在执行的任何一点上,该控件都可以从线程中移除,并交给另一个线程。现在假设function2
已经设置了事件,并且即将在代码中打印**A**
的输出。在打印输出之前,控件被取下并交给功能1
。最后一次打印的输出已经来自function1
,并且它的等待事件已设置,因此它将失败并再次打印其内容
发生这种情况时,您的输出会偶尔出现一次:
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
完成后,即在printf
之后设置事件,您就会没事。缓冲IO代替线程上下文切换是一个残忍无情的婊子。从你的代码中,你是说SetEvent失败了吗?好吧,如果stdout到达终端,它应该是行缓冲的@matrixelk,有重定向吗?另外,看到真实的代码(编译的代码)也很好:这里可能丢失了一些重要的东西。自动重置事件可能会出现时间问题-您是否尝试过手动重置事件并