各位大哥,小弟我最近要做一个模拟线程同步的程序,要求有图形界面,我设计了一下,大体试了一下,但是遇到很多问题,请各位百忙之中看一下,帮我出出主意,不胜感激!(基于单文档应用程序)
一:总体的设想
首先,对于公交车的线路,模拟的话,我是画了一个矩形;
其次,对于站点的模拟,我画了几个实心的圆来代替;
最后,公交车,我用一幅公交车位图来模拟;
二:代码
1:首先是公交线路和站点的模拟部分:
在OnDraw函数中我这样做:
CPen mypen, * oldpen;
mypen.CreatePen(PS_SOLID,10,RGB(0,0,200));
oldpen=(CPen *)pDC->SelectObject(&mypen);
pDC->RoundRect(CRect(100,100,800,500),CPoint(50,50));
pDC->SelectObject(oldpen);
CBrush brush(RGB(153,0,251));
CBrush *oldbrush=pDC->SelectObject(&brush);
pDC->Ellipse(CRect(435,85,465,115));
pDC->Ellipse(CRect(85,285,115,315));
pDC->Ellipse(CRect(435,485,465,515));
pDC->Ellipse(CRect(785,285,815,315));
pDC->SetTextColor(RGB(255,50,0));
pDC->TextOut(400,470,CString("电子科大长安校区"));
pDC->TextOut(130,270,CString("郭杜站"));
pDC->TextOut(420,130,CString("电子商城"));
pDC->TextOut(750,270,CString("电子科大老校区"));
2:其次:我对于公交车的模拟:
我加载了一幅位图:
在OnInitialUpdate()函数中,我这样做:
CView::OnInitialUpdate();
m_static.Create(NULL, WS_CHILD|WS_VISIBLE|SS_BITMAP, CRect(m_carpoint.x, m_carpoint.y, 32, 32), this);
m_static.SetBitmap(LoadBitmap(AfxGetInstanceHandle(), (LPCTSTR)IDB_BITMAP1));
GetParentFrame()->RecalcLayout();
SetTimer(2,1,NULL);
3:线程控制部分:
利用互斥量来实现,建立两个进程分别是公交车司机进程和售票员进程
位图初始化的时候,是m_carpoint.x=450;m_carpoint.y=500;其中m_carpoint是车子的位置,在Ontimer中是这样写的:
if(m_carpoint.x>100&&m_carpoint.y==500&&car_on)
{
m_carpoint.x-=1;
m_static.MoveWindow(m_carpoint.x,500,30,30,true);
}
else if(m_carpoint.x==100&&m_carpoint.y>100&&car_on)
{
m_carpoint.y-=1;
m_static.MoveWindow(100,m_carpoint.y,30,30,true);
}
else if(m_carpoint.x<800&&m_carpoint.y==100&&car_on)
{
m_carpoint.x+=1;
m_static.MoveWindow(m_carpoint.x,100,30,30,true);
}
else if(m_carpoint.x==800&&m_carpoint.y<500&&car_on)
{
m_carpoint.y+=1;
m_static.MoveWindow(800,m_carpoint.y,30,30,true);
}
if(m_carpoint.x==450&&m_carpoint.y==100||
m_carpoint.x==100&&m_carpoint.y==300||
m_carpoint.x==800&&m_carpoint.y==300||
m_carpoint.x==450&&m_carpoint.y==500)
{
car_on=false;
}
else
car_on=true;
我所理解的线程就是:司机在开车之前去判断售票员是否关门了,售票员开门之前看司机是否停车了,XP操作系统给每个线程分配 时间片,用完的话换到宪哥进程,一次实现程序的并发,在我这个例子中,车子是不是停车应该是在Timer中判断,是不是车子到达了指定的站点,司机线程停车,Sleep两秒中,互斥量交给售票员,售票员开门,释放互斥量,交给司机,司机得到door_on是false即车子关了,开车,等等
DWORD WINAPI CZuoyeView::busdriver(LPVOID lpParameter)
{
while(true)
{
if(!door_on)
{
car_on=true;
WaitForSingleObject(hMutex,INFINITE);
Sleep(2000);
}
else
{
//car_on=false;
ReleaseMutex(hMutex);
}
}
return 0;
}
DWORD WINAPI CZuoyeView::conduct(LPVOID lpParameter)
{
while(true)
{
if(!car_on)
{
door_on=true;
WaitForSingleObject(hMutex,INFINITE);
Sleep(2000);
}
else
{
door_on=false;
ReleaseMutex(hMutex);
}
}
return 0;
}
以上是我的线程函数,但是问题来了:首先,在司机线程判断的时候,也许时间片在售票员那里,该售票员判断的时候,也许时间片在司机那里,如果线程里面去判断是不是停车,那就更糟了,因为,是不是停车由一个点决定,是转瞬即逝的,时间片显得很长,会错过好多站点
,这个程序目前是异常状态,希望大家看一看,我也许对线程同步的概念理解的不是很到位,希望大家指导!也许这个程序设计的时候有什么问题?怎么解决车子停车对与m_carpoint的判断?希望你的回帖和意见,不胜感激,我发帖从来都是回帖有分,希望大家给点主意,分不够我再加!!
一:总体的设想
首先,对于公交车的线路,模拟的话,我是画了一个矩形;
其次,对于站点的模拟,我画了几个实心的圆来代替;
最后,公交车,我用一幅公交车位图来模拟;
二:代码
1:首先是公交线路和站点的模拟部分:
在OnDraw函数中我这样做:
CPen mypen, * oldpen;
mypen.CreatePen(PS_SOLID,10,RGB(0,0,200));
oldpen=(CPen *)pDC->SelectObject(&mypen);
pDC->RoundRect(CRect(100,100,800,500),CPoint(50,50));
pDC->SelectObject(oldpen);
CBrush brush(RGB(153,0,251));
CBrush *oldbrush=pDC->SelectObject(&brush);
pDC->Ellipse(CRect(435,85,465,115));
pDC->Ellipse(CRect(85,285,115,315));
pDC->Ellipse(CRect(435,485,465,515));
pDC->Ellipse(CRect(785,285,815,315));
pDC->SetTextColor(RGB(255,50,0));
pDC->TextOut(400,470,CString("电子科大长安校区"));
pDC->TextOut(130,270,CString("郭杜站"));
pDC->TextOut(420,130,CString("电子商城"));
pDC->TextOut(750,270,CString("电子科大老校区"));
2:其次:我对于公交车的模拟:
我加载了一幅位图:
在OnInitialUpdate()函数中,我这样做:
CView::OnInitialUpdate();
m_static.Create(NULL, WS_CHILD|WS_VISIBLE|SS_BITMAP, CRect(m_carpoint.x, m_carpoint.y, 32, 32), this);
m_static.SetBitmap(LoadBitmap(AfxGetInstanceHandle(), (LPCTSTR)IDB_BITMAP1));
GetParentFrame()->RecalcLayout();
SetTimer(2,1,NULL);
3:线程控制部分:
利用互斥量来实现,建立两个进程分别是公交车司机进程和售票员进程
位图初始化的时候,是m_carpoint.x=450;m_carpoint.y=500;其中m_carpoint是车子的位置,在Ontimer中是这样写的:
if(m_carpoint.x>100&&m_carpoint.y==500&&car_on)
{
m_carpoint.x-=1;
m_static.MoveWindow(m_carpoint.x,500,30,30,true);
}
else if(m_carpoint.x==100&&m_carpoint.y>100&&car_on)
{
m_carpoint.y-=1;
m_static.MoveWindow(100,m_carpoint.y,30,30,true);
}
else if(m_carpoint.x<800&&m_carpoint.y==100&&car_on)
{
m_carpoint.x+=1;
m_static.MoveWindow(m_carpoint.x,100,30,30,true);
}
else if(m_carpoint.x==800&&m_carpoint.y<500&&car_on)
{
m_carpoint.y+=1;
m_static.MoveWindow(800,m_carpoint.y,30,30,true);
}
if(m_carpoint.x==450&&m_carpoint.y==100||
m_carpoint.x==100&&m_carpoint.y==300||
m_carpoint.x==800&&m_carpoint.y==300||
m_carpoint.x==450&&m_carpoint.y==500)
{
car_on=false;
}
else
car_on=true;
我所理解的线程就是:司机在开车之前去判断售票员是否关门了,售票员开门之前看司机是否停车了,XP操作系统给每个线程分配 时间片,用完的话换到宪哥进程,一次实现程序的并发,在我这个例子中,车子是不是停车应该是在Timer中判断,是不是车子到达了指定的站点,司机线程停车,Sleep两秒中,互斥量交给售票员,售票员开门,释放互斥量,交给司机,司机得到door_on是false即车子关了,开车,等等
DWORD WINAPI CZuoyeView::busdriver(LPVOID lpParameter)
{
while(true)
{
if(!door_on)
{
car_on=true;
WaitForSingleObject(hMutex,INFINITE);
Sleep(2000);
}
else
{
//car_on=false;
ReleaseMutex(hMutex);
}
}
return 0;
}
DWORD WINAPI CZuoyeView::conduct(LPVOID lpParameter)
{
while(true)
{
if(!car_on)
{
door_on=true;
WaitForSingleObject(hMutex,INFINITE);
Sleep(2000);
}
else
{
door_on=false;
ReleaseMutex(hMutex);
}
}
return 0;
}
以上是我的线程函数,但是问题来了:首先,在司机线程判断的时候,也许时间片在售票员那里,该售票员判断的时候,也许时间片在司机那里,如果线程里面去判断是不是停车,那就更糟了,因为,是不是停车由一个点决定,是转瞬即逝的,时间片显得很长,会错过好多站点
,这个程序目前是异常状态,希望大家看一看,我也许对线程同步的概念理解的不是很到位,希望大家指导!也许这个程序设计的时候有什么问题?怎么解决车子停车对与m_carpoint的判断?希望你的回帖和意见,不胜感激,我发帖从来都是回帖有分,希望大家给点主意,分不够我再加!!
用APIR 几个函数EnterCriticalSection(&g_cs);
LeaveCriticalSection(&g_cs);对其实加入就可以当然用信号量也是可以
这个线程同步应该不难
第一:在线程函数里面的While(true){}这句话不就是说,当这个线程得到时间片??还是这个线程占据互斥事件(我看到的例子中存在没有用互斥事件的,所以应该不是这种情况)?
第二:sleep(2000)的意思是说,这个线程挂起,并且放弃对互斥时间的拥有权,那么这时候互斥事件被谁拥有了??将要发生什么发生,我觉得应该是谁在等待事件,就是哪个进程中有WaitForSingle(ObjecthMutex,INFINITE);,谁就是下一个拥有这个事件的吧!而我要实现的就是在每个站点等待2000毫秒,这个语句是达到这种效果的吗??
第三:WaitForSingle(ObjecthMutex,INFINITE);中的INFINITE意思是,“满足条件”就可以得到对互斥事件的拥有权,对吧?那么“满足条件”是什么意思?我的理解是:当有互斥事件没有人占用的时候,这种说法对吗?是否准确?
第四:我身边有人用信号量,所以我不想用信号量,我要用互斥事件,应该都是一样的吧!所以大家就考虑互斥事件吧!
第五:我在Timer中每隔一毫秒判断一下当前车子的坐标,是否会出现判断失误?意思就是车子到达了站点,但是这个时刻并没有发送货收到timer的消息,造成没有停车的状况?我设计的是1毫秒车子移动单位“1”的距离,所以我认为,不会出现这种状况,大家认为呢?如果我用Ontimer函数中去判断是不是到站,从而决定car_on的true还是false(car_on是判断车子是不是在开动的bool变量),不符合我依靠线程去控制car_on的本质目的,所以不可以这么做
第六:car_on是判断车子是不是在开动的bool变量,这个变量我如果不在Timer中设计,那在线程函数里面判断吗?我觉得那样的会更糟糕!因为,在线程里面用if语句判断的话,鬼知道在我需要判断的时候,是不是有判断语句的线程在执行啊??
第七:我发现在CZuoyeView(大家肯定知道我工程的名字就叫zuoye了)中定义的类成员,在线程函数中竟然不可以访问,所以我一气之下都换成全局变量了?不知道这是什么原因?
第八:在这个题目中,到底线程应该扮演什么角色?“司机在开车之前去判断售票员是否关门了,售票员开门之前看司机是否停车了”就是全部吗??具体应该都写些什么东西?
请高手一一指点····
1,司机等待售票员关门,计时器开始走,2秒后停车,计时器关闭。
2,售票员等待司机停车,开始售票。
3,售票员等待售票完成,关门。用WaitForSingleObject也可以,道理是一样的。
2.sleep表示挂起,互斥事件原来是谁的还是谁的.......
3.infinite表示无限等待....
4.信号量可以有多个,互斥可以看为只有一个资源时的信号量.
5.不会
6.线程可以看为在同时执行(非实时).
7想要访问CZuoyeView的成员,可以考虑传递CZuoyeView的指针,通过CZuoyeView指针来访问,不过不推荐
二,sleep 2000 就是执行到该语句的线程挂起2秒,在大约2000个毫秒以后会被重新排到被操作系统选择的线程中。放弃互斥事件??谁告诉你的?
三,INFINITE字面意思是无限。。WaitForSingleObject就是说无限等待这个信号,你也可以设成等待多少毫秒之后继续执行不等待,具体用法忘了。。请参考msdn。
四,多线程要选用符合实际情况的模型。。
五,不会。
六,会被两个线程访问到的变量,加临界区。
七,类成员对象可以访问啊,要看你怎么访问。。贴出来看看。
八,我上面说了。。
用到两个信号,g_hBusDoorClosed和g_hBusStopped,用来使两个线程交互执行,其实用一个也可以做到,这里为了看到清楚一点,用来两个。
还有一个临界区cs,是发现在cout的时候,线程的交换会导致输出流异常,LZ的图形界面可能也要考虑到这个。#include "stdafx.h"
#include "windows.h"
#include <iostream>using namespace std;CRITICAL_SECTION cs; // Critical section for output, non-related about driver & conductorHANDLE g_hBusDoorClosed; // Global handle of the door's state. if singaled, the door is CLOSED.
HANDLE g_hBusStopped; // Global handle of bus' state, if singaled, the bus is STOPPED.
bool g_bFinish; // Global flag, when bus reach the last stop, make it true.
DWORD WINAPI threadDriverProc( LPVOID lpParam )
{
unsigned short iBusStop = 0; // When bus stops, += 1, only for output. for (;iBusStop < 10;)
{
EnterCriticalSection(&cs);
cout << "Bus now stops at " << iBusStop << endl;
LeaveCriticalSection(&cs); WaitForSingleObject(g_hBusDoorClosed, INFINITE); // Wait until conductor close the door. EnterCriticalSection(&cs);
cout << "Bus now leaves " << iBusStop << endl;
LeaveCriticalSection(&cs); ++ iBusStop;
Sleep(2000);
SetEvent(g_hBusStopped); // Stop the bus.
}
g_bFinish = true;
return 0;
}DWORD WINAPI threadConductorProc( LPVOID lpParam )
{
for (;!g_bFinish;)
{
SetEvent(g_hBusDoorClosed); // Close the door.
WaitForSingleObject(g_hBusStopped, INFINITE); // Wait until driver stop the bus. for (unsigned short i=0; i<3; i++)
{
EnterCriticalSection(&cs);
cout << "Sell ticket to passenger " << i << endl;
LeaveCriticalSection(&cs); Sleep(500);
}
}
return 0;
}int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hDriver;
HANDLE hConductor; InitializeCriticalSection(&cs);
g_hBusDoorClosed = CreateEvent(NULL, false, false, L"g_hBusDoor");
g_hBusStopped = CreateEvent(NULL, false, false, L"g_hBusStopped");
g_bFinish = false; hDriver = CreateThread(
NULL, // default security attributes
0, // use default stack size
threadDriverProc, // thread function
NULL, // argument to thread function
0, // use default creation flags
NULL); // returns the thread identifier hConductor = CreateThread(
NULL, // default security attributes
0, // use default stack size
threadConductorProc, // thread function
NULL, // argument to thread function
0, // use default creation flags
NULL); // returns the thread identifier // Wait until both two threads exit.
WaitForSingleObject(hDriver, INFINITE);
WaitForSingleObject(hConductor, INFINITE); CloseHandle(hDriver);
CloseHandle(hConductor); getchar();
return 0;
}
我的目标是 ----> ^_^
北京思源计算机培训中心(http://www.ciitc.com)