0

我正在尝试使用SetEventWaitForMultipleObjects因此我编写了几个我想使用事件同步的函数。我希望第一个函数执行,然后发出第二个函数执行的信号,这反过来又发出第一个函数再次执行的信号,依此类推。

创建了两个事件,一个初始化为有信号状态,另一个初始化为无信号状态。我可以让执行按预期进行的唯一方法是让每个线程休眠 10 毫秒。我阅读了有关使用 SetEvent 的一些注意事项:http: //cboard.cprogramming.com/windows-programming/100818-setevent-resetevent-3.html

我的问题是我必须让我的线程进入睡眠状态,因为这些函数调用需要额外的时间来实际发出事件信号吗?有时调试时,设置的事件仍然未发出信号。我使用流程资源管理器验证了这一点。我的代码基本上是这样的:

主要是:

//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 循环中运行几次,而不是在两个函数之间来回反复。有任何想法吗?

4

3 回答 3

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");
}

内核抢占了正在运行的线程,function2因此FinUpdatestructCalcpid现在已经设置了事件,而没有printf您期望的对应。

然后执行正在运行的线程function1并设置FinUpdatestructCalcpid事件。现在允许正在运行的线程function2执行并从它停止的地方继续。它运行printf并且因为FinUpdatestructCalcpid事件已经设置它立即再次运行。

您正在使用的Sleep()调用有助于使这种竞争条件不太可能发生,但不要消除它。

于 2013-01-11T07:24:02.793 回答
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,你会没事的。

于 2013-01-11T08:09:18.700 回答
0

这就是我的想法...

在设置事件之前,您不会输出任何状态。那时,执行可能会在您输出任何内容之前切换到另一个线程。如果该线程首先运行,那么它可能看起来好像一个线程的循环已经运行了第二次——一个没有乒乓球的 ping ...

但是,如果您要在接收信号和设置事件之间增加一个全局计数器,然后将该计数器的值保存到一个局部变量中,您可能会发现一个线程的计数总是奇数,而另一个线程的计数总是偶数(这是你想要的行为),即使输出不是很有序。

于 2013-01-11T03:40:27.573 回答