请教一个简单的线程问题,重复输出!!

proware 2005-09-15 01:51:39
/*
05-09-15
两个线程同时对一个变量进行写操作,
他们之间的互斥的问题。
*/
#include <windows.h>
#include <iostream.h>
int tickets=20;
DWORD WINAPI FirstSell(
LPVOID lpParameter // thread data
);
DWORD WINAPI SecondSell(
LPVOID lpParameter // thread data
);

void main()
{
HANDLE hThread1;
HANDLE hThread2;
hThread1=CreateThread(NULL,0,FirstSell,NULL,0,NULL);
hThread2=CreateThread(NULL,0,SecondSell,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(100);

}
DWORD WINAPI FirstSell(
LPVOID lpParameter // thread data
)
{
while(tickets!=0)
{
cout<<"thread1 sell:"<<tickets--<<endl;

}
return 0;
}
DWORD WINAPI SecondSell(
LPVOID lpParameter // thread data
)
{
while(tickets!=0)
{
cout<<"thread2 sells:"<<tickets--<<endl;

}
return 0;
}
上面的程序的输出是:
thread1 sell:20
thread1 sell:19
thread1 sell:18
thread1 sell:17
thread1 sell:16
thread1 sell:15
thread1 sell:14
thread1 sell:13
thread1 sell:12
thread1 sell:11
thread1 sell:10
thread1 sell:9
thread1 sell:8
thread1 sell:7
thread1 sell:6
thread1 sell:5 //重复输出的地方
thread1 sell:5
thread2 sells:4
thread2 sells:3
thread2 sells:2
thread2 sells:1
Press any key to continue
为什么在第一个线程的结束的时候,它重复的输出呢?
还请指教,谢谢!!!
...全文
223 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
jjiaming 2005-11-30
  • 打赏
  • 举报
回复
另外,在我的机器上运行你的代码,结果是两次输出6,呵呵
jjiaming 2005-11-30
  • 打赏
  • 举报
回复
楼主,今天在看windows程序调试时,突然想到你的贴子,我想你的问题我已经知道答案了
首先来看看tickets--的汇编代码;
00401152 8B 15 50 8D 42 00 mov edx,dword ptr [tickets (00428d50)]
00401158 83 EA 01 sub edx,1
0040115B 89 15 50 8D 42 00 mov dword ptr [tickets (00428d50)],edx
第一句是把tickets的值放入edx寄存器中,第二句是把edx寄存器中的值减一,第三句是把
把edx寄存器中的值放入tickets中.通过这样实现tickets的值减一.好,现在分析一下为什么会重复输出,当tickets为6且线程1执行完第二句sub edx,1时(此时tickets仍为6,edx的值为5),这时系统切换到线程2执行,执行完tickets--后,tickets为5,edx的值也为5.此时输出5,现在如果系统又切换到线程1执行,那么会执行第三句:
mov dword ptr [tickets (00428d50)],edx
此时edx的值为5,tickets的值也为5,所以会再次输出5.
所有对于多线程,必须用汇编代码的级别上考虑问题.

proware 2005-09-22
  • 打赏
  • 举报
回复
无奈,问题得不到解决也要结贴..>!!失望!!!!!!!!!!!!!!
alen_ghl 2005-09-19
  • 打赏
  • 举报
回复
晕,搞错了
当我什么也没说~!
alen_ghl 2005-09-19
  • 打赏
  • 举报
回复
to football(gugu)
我想你应该先实践一下,再发表一下你的看法^_^

此问题看起来确实很怪,重复值只在第一次线程切换的时候发生,而且肯定是初值tickets(20)-15 = 5 的时候,如果初值tickets<=15不出现(根本就没有线程切换),tickets >15将出现重复,
但无论你的tickets 多大,重复运行多少次,就只在tickets-15的地方重复,有且只有一次!
这时你可能发现,问题不是因为线程的切换,如果是那样后面也应该有,也不是临界区的问题,
因为运行多次,结果都一样
那问题就出现在2个线程的创建上,在
hThread1=CreateThread(NULL,0,FirstSell,NULL,0,NULL);
Sleep(1); //注意这个
hThread2=CreateThread(NULL,0,SecondSell,NULL,0,NULL);
然后把tickets换成足够大,使之能切换到第二个线程,问题就不再出现了

之所以这样,我也不太清楚,可能跟WINDOWS内核有关吧
casinosun 2005-09-18
  • 打赏
  • 举报
回复
用临界区吧
proware 2005-09-17
  • 打赏
  • 举报
回复
楼上的说的对呀!
用mutex的确可以解决的.我已经用过.
就是不知道出现我的问题的原因,而我现在就想知道这个的.
phoenix96_2000 2005-09-16
  • 打赏
  • 举报
回复
上次没看仔细,刚刚试了一遍,的确是这样,而且每次都是出来2遍5; 使用InterlockedDecrement也一样
都是在第一次线程要切换到第二个线程的时候出现这个问题
我也解释不清楚这是为什么..

如果两个启动都是FirstSell或者把打印放到一个函数中去,那么使用CriticalSection就可以解决问题

由于你是启动的是两个函数,是有两处代码,因此使用CriticalSection不行,
但是ticket是临界资源,因此可以用Mutex来解决,下面是我的代码:


// TestThread.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <iostream.h>
long tickets=100;
DWORD WINAPI FirstSell(
LPVOID lpParameter // thread data
);
DWORD WINAPI SecondSell(
LPVOID lpParameter // thread data
);

HANDLE g_hMutex;

void main()
{
g_hMutex = CreateMutex(NULL,FALSE,"test");
ReleaseMutex(g_hMutex); // 先release.. 不然大家都得等到被Ctrl^C :)

HANDLE hThread[2];
hThread[0] = CreateThread(NULL,0,FirstSell,NULL,CREATE_SUSPENDED,NULL);
hThread[1] = CreateThread(NULL,0,SecondSell,NULL,CREATE_SUSPENDED,NULL);

ResumeThread(hThread[0]);
ResumeThread(hThread[1]);

WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(g_hMutex);
}
DWORD WINAPI FirstSell(
LPVOID lpParameter // thread data
)
{
while(tickets!=0)
{
if(WaitForSingleObject(g_hMutex,INFINITE) == WAIT_OBJECT_0)
{
printf("thread1 sell %.2d\n",tickets--);
ReleaseMutex(g_hMutex);

}
}
return 0;
}
DWORD WINAPI SecondSell(
LPVOID lpParameter // thread data
)
{

while(tickets!=0)
{
if(WaitForSingleObject(g_hMutex,INFINITE) == WAIT_OBJECT_0)
{
printf("thread2 sell %.2d\n",tickets--);
ReleaseMutex(g_hMutex);
}
}
return 0;
}
proware 2005-09-16
  • 打赏
  • 举报
回复
用临界区同步一下。

\\\\\\\\\\\\\\\
这个我用了,刚出现问题的时候就用了,不会出现重复.

但是临界不是两个线程或多个线程时,才要使临界资源同步,
但是我的 在第一个线程时发生了重复的情况,看起来跟第二个线程
没有多大关系嘛.
还望仔细说明其中的原因.谢谢!!
football 2005-09-16
  • 打赏
  • 举报
回复
典型的临界资源问题.多执行几次,会出现重复的情况很多。

可以用phoenix96_2000(eXMe)的方法去解决问题。
qq_lhz 2005-09-16
  • 打赏
  • 举报
回复
一个线程显示2次相同值,想不出原因!
gengmingxia 2005-09-15
  • 打赏
  • 举报
回复
如果循环多一些,或循环里加延时,看一下结果
gengmingxia 2005-09-15
  • 打赏
  • 举报
回复
如果循环多一些,或循环里加延时,看一下结果
gengmingxia 2005-09-15
  • 打赏
  • 举报
回复
是不是运行几个循环时间片足够长。
phoenix96_2000 2005-09-15
  • 打赏
  • 举报
回复
同步问题
使用InterlockedDecrement来替代 ticket--
jjiaming 2005-09-15
  • 打赏
  • 举报
回复
确定有些奇怪, 关注
rageliu 2005-09-15
  • 打赏
  • 举报
回复
up
DentistryDoctor 2005-09-15
  • 打赏
  • 举报
回复
用临界区同步一下。

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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