回 帖 发 新 帖 刷新版面

主题:[讨论]C++多线程EVENT同步

不知道为什么,偶根据孙老师的例子<VC教学视频\Lesson16\Code\Event>测试用EVENT进行线程同步时候,结果老是出乎意料。

程序大体是 先创建两个立即执行的线程售票,再创建一个事件对线程进行控制。
程序开始先创建两个立即执行的线程,然后创建自动重置的事件。
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
SetEvent( g_hEvent );

线程函数体是:
while(TRUE)
 {
  WaitForSingleObject(g_hEvent,INFINITE);   // g_hEvent是事件的句柄

  if(tickets>0)                             // tickets是票号, 初始为100,即只可能售出票号为1,2,---, 100的票
  {
   Sleep(1);
   cout<<"thread1 sell ticket : "<<tickets--<<endl;
  }
  else
   break;
  SetEvent(g_hEvent);               //    置事件为有信号状态
}

可是偶在电脑上<单CPU>运行多几次,就会出现 "thread* sell ticket: 0 ". 

我想,会不会是这样,假设线程1在WaitForSingleObject函数里获知事件有信号,可还没来得及重置事件信号时候,它的时间片就结束了,然后线程2获得信号,这样就有机会售出“0”票了。
 但当,先创建事件,再创建两个立即执行的线程,结果就正常了。
如果上面的想法正确的话,为什么调整下创建事件跟线程的顺序就行了呢??

还有在单CPU下,这些多线程同步是不是只是宏观上的同步,因为单句语句转换为机器指令的时候可能为多句,这样,在多句机器指令中都有几率遇上CPU时间结束,那就没真正意义上的同步了。

望高手大侠不啬赐教。谢谢。 ~
[code=c]
#include <windows.h>
#include <iostream.h>

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
);

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
);

int tickets=100;
HANDLE g_hEvent;

void main()
{
 HANDLE hThread1;
 HANDLE hThread2;
 hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
 hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
 CloseHandle(hThread1);
 CloseHandle(hThread2);

           //将以下两句放到 CreateThread 前执行,结果就正常了~
 g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
  SetEvent(g_hEvent);



 Sleep(4000);
 CloseHandle(g_hEvent);
}

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
 while(TRUE)
 {
  WaitForSingleObject(g_hEvent,INFINITE);
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread1 sell ticket : "<<tickets--<<endl;
  }
  else
   break;
  SetEvent(g_hEvent);
 }
 
 return 0;
}

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
)
{
 
 while(TRUE)
 {
  WaitForSingleObject(g_hEvent,INFINITE);
  if(tickets>0)
  {
   Sleep(1);
   cout<<"thread2 sell ticket : "<<tickets--<<endl;
  }
  else
   break;
  SetEvent(g_hEvent);
 }
 
 return 0;
}

[/code]

回复列表 (共1个回复)

沙发

找到了孙老师的VC++视频勘误和说明

四、在视频Lesson16的事件代码中,有一个问题,修改如下:

void main() { HANDLE hThread1; HANDLE hThread2;

g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); //将CreateEvent()函数放置在这个位置

hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL); hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2);

//g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//取消这个位置的CreateEvent()函数。

/*g_hEvent=CreateEvent(NULL,FALSE,FALSE,"tickets"); if(g_hEvent) { if(ERROR_ALREADY_EXISTS==GetLastError()) { cout<<"only instance can run!"<<endl; return; } }*/ SetEvent(g_hEvent);

Sleep(4000); CloseHandle(g_hEvent); }

原因:如果在线程产生之后调用CreateEvent(),假如线程提前被操作系统调度,那么线程里的 WaitForSingleObject 等待的将是一个空的g_hEvent, 在这种情况下,WaitForSingleObject 将返回WAIT_FAILED 。这个问题可以通过在CreateEvent()函数前添加Sleep(10)的调用来查看。


五、在视频Lesson16的采用事件的多线程同步代码中,有一个问题:在线程1和线程2的代码中,有下面一段:

while(TRUE) { WaitForSingleObject(g_hEvent,INFINITE); if(tickets>0) { Sleep(1); cout<<"thread1 sell ticket : "<<tickets--<<endl; } else break; SetEvent(g_hEvent); }

这个代码有一个问题,当线程1或线程2卖完最后一张票时,调用SetEvent(g_hEvent);将事件对象设置为有信号状态,另一个线程等待到事件对象,开始执行代码,判断tickets不大于0,于是执行else语句下的break,退出循环,此时SetEvent(g_hEvent);就没有被执行,导致线程1或线程2一直等待,直到主线程终止运行,整个程序才退出。应将SetEvent(g_hEvent);在 if 和 else 中分别调用,修改如下:

DWORD WINAPI Fun1Proc( LPVOID lpParameter // thread data ) { while(TRUE) { WaitForSingleObject(g_hEvent,INFINITE); // ResetEvent(g_hEvent); if(tickets>0) { Sleep(1); cout<<"thread1 sell ticket : "<<tickets--<<endl; SetEvent(g_hEvent); } else { SetEvent(g_hEvent); break; } } return 0; }

DWORD WINAPI Fun2Proc( LPVOID lpParameter // thread data ) { while(TRUE) { WaitForSingleObject(g_hEvent,INFINITE); // ResetEvent(g_hEvent); if(tickets>0) { Sleep(1); cout<<"thread2 sell ticket : "<<tickets--<<endl; SetEvent(g_hEvent); } else { SetEvent(g_hEvent); break; } } return 0; }

大概知道了,先创建线程在创建事件,可能线程提前被操作系统调度,那么此时查看GetLastError返回的错误是:句柄无效。事件还没来得及对线程进行同步。

不过后面的:
还有在单CPU下,这些多线程同步是不是只是宏观上的同步,因为单句语句转换为机器指令的时候可能为多句,这样,在多句机器指令中都有几率遇上CPU时间结束,那就没真正意义上的同步了。
还是不太明白,到底是不是这样的。
还请高手大侠不啬赐教。谢谢。 ~

我来回复

您尚未登录,请登录后再回复。点此登录或注册