2013-04-01 38 views
0

我有这样的代码:这个同步为什么不起作用?

#include <windows.h> 
#include <tchar.h> 
#include <stdio.h> 
#include <stdlib.h> 

#include <time.h> 

#define ITERATIONS 10 

typedef struct NUMERE 
{ 
    DWORD a; 
    DWORD b; 
} *PNUMERE; 

HANDLE ghThreadHandle[2]; 
HANDLE ghEvents[2]; 
//HANDLE hEvent; 

NUMERE nr; 

DWORD WINAPI GenerateNumbers(PNUMERE nr) 
{ 
    //PNUMERE nr = ((PNUMERE)param); 
    if(nr == NULL) 
     return -1; 

    nr->a = rand() % 100; 
    nr->b = (nr->a) * 2; 

    _tprintf(TEXT("Generated\n")); 

    //Sleep(10); 

    return 0; 
} 

DWORD WINAPI DisplayNumbers(PNUMERE nr) 
{ 
    //NUMERE nr = *((PNUMERE)param); 

    _tprintf(TEXT("Displayed: %d %d\n"),nr->a,nr->b); 

    return 0; 
} 

DWORD WINAPI DoStuff(PVOID param) 
{ 
    int index = *((int*)param); 

    for(unsigned int i = 0 ; i < ITERATIONS ; i++) 
    { 
     if(index == 0) 
     { 
      WaitForSingleObject(ghEvents[1],INFINITE); 
      ResetEvent(ghEvents[0]); 

      if(GenerateNumbers(&nr) == -1) 
       _tprintf(TEXT("GenerateNumbers error!\n")); 

      SetEvent(ghEvents[0]); 
      ResetEvent(ghEvents[1]); 
     } 
     else 
     { 
      WaitForSingleObject(ghEvents[0],INFINITE); 
      ResetEvent(ghEvents[1]); 

      DisplayNumbers(&nr); 

      SetEvent(ghEvents[1]); 
      ResetEvent(ghEvents[0]); 
     } 
    } 

    return 0; 
} 

DWORD GenerateThreads() 
{ 
    int temp0 = 0, temp1 = 1; 
    ghThreadHandle[0] = CreateThread(NULL 
     ,0 
     ,(LPTHREAD_START_ROUTINE)DoStuff 
     ,(LPVOID)&temp0 
     ,0 
     ,NULL); 

    if(NULL == ghThreadHandle[0]) 
     return -1; 

    ghThreadHandle[1] = CreateThread(NULL 
     ,0 
     ,(LPTHREAD_START_ROUTINE)DoStuff 
     ,(LPVOID)&temp1 
     ,0 
     ,NULL); 

    if(NULL == ghThreadHandle[1]) 
    { 
     CloseHandle(ghThreadHandle[0]); 
     return -1; 
    } 

    return 0; 
} 

int main() 
{ 
    srand(time(NULL)); 

    ghEvents[0] = CreateEvent(NULL,TRUE,TRUE,TEXT("MyEvent0")); 
    ghEvents[1] = CreateEvent(NULL,TRUE,TRUE,TEXT("MyEvent1")); 

    if(NULL == ghEvents[0] || NULL == ghEvents[1]) 
    { 
     _tprintf("Error creating events\n"); 
     return -1; 
    } 

    if(GenerateThreads() == -1) 
    { 
     _tprintf("Error GenerateThreads\n"); 
     return -1; 
    } 

    WaitForMultipleObjects(2,ghThreadHandle,TRUE,INFINITE); 

    //getchar(); 

    CloseHandle(ghThreadHandle[0]); 
    CloseHandle(ghThreadHandle[1]); 

    CloseHandle(ghEvents[0]); 
    CloseHandle(ghEvents[1]); 

    return 0; 
} 

我想这两个功能(GenerateNumbersDisplayNumbers)将可称为。但是,启动后,GenerateNumbers被调用两次,然后它只是等待。方法永远不会被调用。有人能解释这个僵局的原因吗?

+1

你的例子不是独立的。你不清楚你传递了什么'param'或者你创建了多少个线程。还要注意,你创建了两个事件最初发信号,所以你有一个竞争条件马上。 –

+0

我创建了两个线程。它们都接收一个int作为参数(第一个用0初始化,第二个用1初始化)。这不是问题。我测试过了。 – conectionist

+0

由于两个事件都是在初始状态发出信号的情况下创建的,所以两个线程都同时运行第一次迭代,此时事情就会快速下降。此外,同步代码在完成其清理(重置唤醒事件)之前释放其他线程,这可能会创建其他竞态条件。插入一些打印语句以查看发生了什么。 –

回答

3

GenerateThreads函数将局部变量的地址传递给另一个线程(temp0temp1)。该函数在启动线程后立即返回。这意味着其他线程正在访问已释放的内存。看起来,当线程读取它们的param时,内存将值更改为零,所以两个线程都认为它们是线程的GenerateNumbers

添加额外的调试打印语句可能会更快地发现此问题。

请注意,由于您在重置唤醒事件之前指示其他线程开始启动,因此每个块的末尾仍有竞争状态。另一个线程可能会在第一个线程从SetEvent返回之前醒来,完成它的工作,然后设置唤醒事件。第一个线程然后重置其事件并等待它,使其失去唤醒事件并因此挂起。

+0

感谢万! – conectionist