双CPU,多线程同步问题,大虾请进!

aa335418265 2012-09-27 11:21:21
当我们使用内核对象(如事件内核对象)进行2线程同步的时候,是否会发生如下情况:
两个线程都是第一次启动时候,同时获取到内核对象的使用权?我觉得会发生,上代码:

#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情况下,两个线程是否有可能都同时获取到信号?
...全文
176 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
fxworld 2012-09-28
  • 打赏
  • 举报
回复


二楼的分析比较到位,是楼主的程序逻辑(执行顺序)有问题,将CreateEvent函数放到创建线程的前面可以解决线程等待事件对象的问题。
BORLANDSUN 2012-09-28
  • 打赏
  • 举报
回复
我觉得不会,OS会把这个细节屏蔽掉。楼主试试在双核CPU上会不会也有这个问题。
aa335418265 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]
我觉得不会,OS会把这个细节屏蔽掉。楼主试试在双核CPU上会不会也有这个问题。
[/Quote]

我的就是双核CPU了,看看2楼的分析,我感觉有道理!
aa335418265 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]
我给你分析一下

首先,你的两个子线程是非挂起创建,创建后两线程就开始执行了,
创建后os对你的进程至少3个线程开始调度,而你的Event对象这个时候还不知道在哪里,
WaitForSingleObject也没判断返回值,那么,会发生什么?
好吧,在你的event事件对象创建之前你线程中的WaitForSingleObject函数会返回失败,
当然,在你这代码里就是继续往下走并继续循环……
[/Quote]

分析的有道理,原来是这样的情况!谢谢了
aa335418265 2012-09-28
  • 打赏
  • 举报
回复
[Quote=引用楼主 的回复:]
当我们使用内核对象(如事件内核对象)进行2线程同步的时候,是否会发生如下情况:
两个线程都是第一次启动时候,同时获取到内核对象的使用权?我觉得会发生,上代码:

#include <windows.h>
#include <iostream.h>

DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD ……
[/Quote]


我的就是双核CPU了
dataxdata 2012-09-28
  • 打赏
  • 举报
回复
这种情况应该使用互斥量Mutex,而不是使用通知事件Event进行同步
yoke_wolf 2012-09-28
  • 打赏
  • 举报
回复
我给你分析一下

首先,你的两个子线程是非挂起创建,创建后两线程就开始执行了,
创建后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);


你这问题是关于事件对象的,我就只说他们相关的,其他问题我就不说了

1,316

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧