双CPU,多线程同步问题,大虾请进!
当我们使用内核对象(如事件内核对象)进行2线程同步的时候,是否会发生如下情况:
两个线程都是第一次启动时候,同时获取到内核对象的使用权?我觉得会发生,上代码:
[code=C/C++][/code]
#include <windows.h>
#include <iostream.h>
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
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);
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
SetEvent(g_hEvent);
Sleep(4000);
}
DWORD WINAPI Fun1Proc(
LPVOID lpParameter
)
{
while(TRUE)
{ //Sleep(10); 不加此行代码时候,结果经常会出现 :
//thread2 sell ticket 100
//thread1 sell ticket 99
WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{ Sleep(1);
cout<<"thread1 sell ticket :"<<tickets--<<endl;
}
else
break;
}
return 0;
}
DWORD WINAPI Fun2Proc(
LPVOID lpParameter
)
{
while(TRUE)
{ WaitForSingleObject(g_hEvent,INFINITE);
if(tickets>0)
{
cout<<"thread2 sell ticket :"<<tickets--<<endl;
}
else
break;
}
return 0;
}
结果有两种:
1) thread2 sell ticket :100
2) thread2 sell ticket :100
thread1 sell ticket :99
按照我的分析,出现结果2的原因为:因我的电脑是双CPU的,所以第一次两个线程可能同时都得到事件内核对象处于信号状态,于是两个线程都获取到了对WaitForSingleObject函数一下的代码的使用权,但是由于线程1的Sleep(1)的存在,所以线程2先完成了cout<<"thread2 sell ticket :"<<tickets--<<endl;这行代码的执行.所以线程2打印100,之后线程1睡眠过后,接着执行cout<<"thread1 sell ticket :"<<tickets--<<endl;这行代码.(因为是自动重置,所以内核对象会一直处于没信号状态,两个线程都不能接着打印!)
不知道我的分析对不对呢?我想问的是,在双CPU情况下,两个线程是否有可能都同时获取到信号?
[解决办法]
我给你分析一下
首先,你的两个子线程是非挂起创建,创建后两线程就开始执行了,
创建后os对你的进程至少3个线程开始调度,而你的Event对象这个时候还不知道在哪里,
WaitForSingleObject也没判断返回值,那么,会发生什么?
好吧,在你的event事件对象创建之前你线程中的WaitForSingleObject函数会返回失败,
当然,在你这代码里就是继续往下走并继续循环,输出内容,这个过程持续的你的event对象创建完成,
这个过程时间取决于硬件配置,速度,系统调度规则等等,
很显然,这个过程产生的输出是不可预调的
其次,我们再看你的事件对象的创建。你创建的是非管理重置,初始状态为无信号状态的event object,
所以,在前面说的那个过程结束,你的对象创建后,两线程会开始等待事件信号,直到你的SetEvent(g_hEvent)执行完成,此时,其中一个幸运的子线程将会得到事件信号,由于你的事件是非管理重置,你的event对象自动重置为无信号状态,该线程继续输出相关内容然后继续等待。当然,事件现在处于无信号状态,而你的程序再也没用SetEvent的调用发生,所以,直到你程序结束,再也没人能等到你的event信号了。
从上可知,你程序现在的结果是: 一系列不可预料的输出(包括可能什么都没有) + 某个幸运线程的一条输出 = 不可预料的输出
改下面两个步骤,你应该可以看到想要的结果, 至于为什么,说了那么多,应该可以想明白了
1.把
g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
放到
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
这一行前面
2. 在你两个线程循环中的break; 后面都加一行 SetEvent(g_hEvent);
你这问题是关于事件对象的,我就只说他们相关的,其他问题我就不说了