我正在尝试使用SetEvent
和WaitForMultipleObjects
,因此我编写了一些我希望使用Events进行同步的函数。我希望第一个函数执行,然后发出第二个函数执行信号,这反过来表示第一个函数再次执行等。
创建了两个事件,一个初始化为信号状态,另一个未信号。我可以让执行按预期流动的唯一方法是让每个线程休眠10毫秒。我读到了一些关于使用SetEvent的注意事项: http://cboard.cprogramming.com/windows-programming/100818-setevent-resetevent-3.html
我的问题是我必须让我的线程进入睡眠状态,因为这些函数调用需要额外的时间来实际发出事件信号吗?在调试时,有时设置的事件仍然是无信号的。我使用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)
如果没有使用睡眠,那么有时相同的功能将在while循环中运行几次,而不是在两个函数之间来回ping。有什么想法吗?
答案 0 :(得分:3)
您可以在每项功能的printf
电话上方添加SetEvent
来解决问题。
问题是你正在设置事件然后执行一些输出。
在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");
}
内核preempts正在运行function2
的线程,因此现在已设置FinUpdatestructCalcpid
事件,而没有您期望的相应printf
。
然后执行运行function1
的线程并设置FinUpdatestructCalcpid
事件。现在允许运行function2
的线程执行并从它停止的位置继续。它运行printf
,因为FinUpdatestructCalcpid
事件已设置,它会立即再次运行。
Sleep()
调用你正在使用帮助来使这种竞争条件不太可能,但不要消除它。
答案 1 :(得分:1)
首先让我简短地删除您的代码:
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**
周围的输出。在打印输出之前,控件被取走并提供给function1
。最后打印的输出已经来自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
之后,您就可以了。
答案 2 :(得分:0)
这就是我的想法......
在您设置事件之前,不输出任何状态。此时,执行可以在输出任何内容之前切换到另一个线程。如果该线程首先运行,那么它可能看起来好像一个线程的循环已经运行了第二次 - 没有乒乓的ping ...
但是如果要在接收信号和设置事件之间递增全局计数器,然后将该计数器的值保存到局部变量,您可能会发现一个线程的计数总是奇数而另一个总是偶数(这是你想要的行为),即使输出不是很有序。