首先声明的是,现在程序已经能基本运行起来了,但偶尔会出现一些莫名其妙的错误,百思不得其解,麻烦各位了,
在我程序中,参考了很多网友的代码,在此谢过各位网友了,但是有很多地方不是很明白,烦请大家帮忙解解疑。
程序的工作原理和流程:
每建立一个CDlgInfo对话框,都启一个定时器(定时器11,每隔2s定时一次),然后这个定时器判断当前是否有扫描底层数据
的线程在运行,如果没有则开启一个线程,否则什么也不做,等待下一次定时消息,再判断,如果已经有线程运行过,并已经
结束了,则释放以前线程的资源,并且再启一个线程继续扫描。
当开启扫描底层数据的线程后,则给底层发送数据,如果底层设备是有电的,则它将返回相应的数据给上层,如此循环执行下去,
如果某个时刻底层设备没电了(通过底层是否返回数据了来判断),则退出循环,并结束当前线程,在此期间,当线程启动时,并
开启一个定时器,来不断地刷新当前对话框的内容,如果当前设备没电了,则不再刷新。此外,上层发送数据后,底层会返回相应
的数据,这时候程序会接收到(wMsg消息,这是自定义的),紧接着就会触发OnRecv函数来接收数据并将数据送到指定的位置。现在有几个问题想问问大家,请大家帮帮忙,在此谢过了.
1.整个程序的组织有没有什么不正确的地方,该怎么修改,特别是关于线程的地方。(这个问题是最关键的问题)2.下面就涉及到细节问题了,在线程函数ScanThread里的pDlg->SetTimer(13,100,NULL);这个地方我启动了一个定时器
这个定时器是否有主线程来执行,消息也是由主线程来接收,在这个线程函数里,是不是要做些额外的工作(比如转发消息)3.发送数据后,底层返回相应的数据,这时候触发的wMsg消息是不是也由主线程来接收还是ScanThread线程接收,我在等待
ScanThread线程接收数据时,转发了消息,是不是起了作用?最搞不懂的是,我现在的线程是个工作线程,这里面的消息究竟是怎么传递的,
怎么接收的?4.在ScanThread线程中,为了以后能够让主线程也能发送一些包到底层数据和防止ScanThread多次启动执行(同时只能由一个线程向底层发送
数据,并且发送数据后必须等待一段时间来接收数据,虽然这个时间很短,但不能再有数据发送下去),我这里用了一个信号量来做同步和互斥,
不知可否,是不是要采用一些其他的同步对象,比如临界区,互斥等。5.在OnDestroy()里while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
}
为什么要加上这一句呢,MsgWaitForMultipleObjects不是自己可以接收转发消息吗?6.这个问题呆会儿加
程序清单:#define wMsg WM_USER+5 //用于接收底层数据
class CDlgInfo : public CDialog
{
// Construction
public:
BOOL m_bJijiaFlag;
CSemaphore *sem;//信号量
CMainFrame *m_pParent;//当前线程指针
static UINT ScanThread(LPVOID pParam);//自己的线程函数
volatile BOOL m_bPowerFlag;//当前设备是否有电标志位
void OnRecv(WPARAM wParam, LPARAM lParam);//接收底层数据的消息接收函数
//省略若干
} BOOL CDlgInfo::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
m_bPowerFlag=FALSE;//刚开始,设备是没电的
pScanThread=NULL;//线程指针置为空
m_bReceived=FALSE;
sem=new CSemaphore();//申请一个信号量资源
//启动定时器,扫描设备是否存在,如果存在,即开启扫描线程
SetTimer(11,2000,NULL);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
UINT CDlgInfo::ScanThread( LPVOID pParam)
{
CDlgInfo *pDlg=(CDlgInfo *)pParam;
//创建一个CSingleLock对象,初始化为信号量sem
CSingleLock singlock(pDlg->sem);
//当前还未刷新界面
pDlg->m_bRefreshFlag=FALSE;
do
{
//锁信号量
singlock.Lock();
//发送snmp包到底层
pDlg->SendSnmp(); //当前设备有电,并且当前还未刷新界面,则开启定时器13,没隔100ms刷新一次
if((pDlg->m_bPowerFlag==TRUE)&&(pDlg->m_bRefreshFlag==FALSE))
{
pDlg->m_bRefreshFlag=TRUE;//已经开启定时器刷新界面了,不需要再次开启了
pDlg->SetTimer(13,100,NULL);
}
//开信号量
singlock.Unlock();
//休眠1000ms
Sleep(1000);
}
while(pDlg->m_bPowerFlag==TRUE);//当前设备还有电,则继续扫描 pDlg->KillTimer(13);//线程即将退出,将刷新界面定时器关掉,不再刷新界面了
return 0;
}
在我程序中,参考了很多网友的代码,在此谢过各位网友了,但是有很多地方不是很明白,烦请大家帮忙解解疑。
程序的工作原理和流程:
每建立一个CDlgInfo对话框,都启一个定时器(定时器11,每隔2s定时一次),然后这个定时器判断当前是否有扫描底层数据
的线程在运行,如果没有则开启一个线程,否则什么也不做,等待下一次定时消息,再判断,如果已经有线程运行过,并已经
结束了,则释放以前线程的资源,并且再启一个线程继续扫描。
当开启扫描底层数据的线程后,则给底层发送数据,如果底层设备是有电的,则它将返回相应的数据给上层,如此循环执行下去,
如果某个时刻底层设备没电了(通过底层是否返回数据了来判断),则退出循环,并结束当前线程,在此期间,当线程启动时,并
开启一个定时器,来不断地刷新当前对话框的内容,如果当前设备没电了,则不再刷新。此外,上层发送数据后,底层会返回相应
的数据,这时候程序会接收到(wMsg消息,这是自定义的),紧接着就会触发OnRecv函数来接收数据并将数据送到指定的位置。现在有几个问题想问问大家,请大家帮帮忙,在此谢过了.
1.整个程序的组织有没有什么不正确的地方,该怎么修改,特别是关于线程的地方。(这个问题是最关键的问题)2.下面就涉及到细节问题了,在线程函数ScanThread里的pDlg->SetTimer(13,100,NULL);这个地方我启动了一个定时器
这个定时器是否有主线程来执行,消息也是由主线程来接收,在这个线程函数里,是不是要做些额外的工作(比如转发消息)3.发送数据后,底层返回相应的数据,这时候触发的wMsg消息是不是也由主线程来接收还是ScanThread线程接收,我在等待
ScanThread线程接收数据时,转发了消息,是不是起了作用?最搞不懂的是,我现在的线程是个工作线程,这里面的消息究竟是怎么传递的,
怎么接收的?4.在ScanThread线程中,为了以后能够让主线程也能发送一些包到底层数据和防止ScanThread多次启动执行(同时只能由一个线程向底层发送
数据,并且发送数据后必须等待一段时间来接收数据,虽然这个时间很短,但不能再有数据发送下去),我这里用了一个信号量来做同步和互斥,
不知可否,是不是要采用一些其他的同步对象,比如临界区,互斥等。5.在OnDestroy()里while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
}
为什么要加上这一句呢,MsgWaitForMultipleObjects不是自己可以接收转发消息吗?6.这个问题呆会儿加
程序清单:#define wMsg WM_USER+5 //用于接收底层数据
class CDlgInfo : public CDialog
{
// Construction
public:
BOOL m_bJijiaFlag;
CSemaphore *sem;//信号量
CMainFrame *m_pParent;//当前线程指针
static UINT ScanThread(LPVOID pParam);//自己的线程函数
volatile BOOL m_bPowerFlag;//当前设备是否有电标志位
void OnRecv(WPARAM wParam, LPARAM lParam);//接收底层数据的消息接收函数
//省略若干
} BOOL CDlgInfo::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
m_bPowerFlag=FALSE;//刚开始,设备是没电的
pScanThread=NULL;//线程指针置为空
m_bReceived=FALSE;
sem=new CSemaphore();//申请一个信号量资源
//启动定时器,扫描设备是否存在,如果存在,即开启扫描线程
SetTimer(11,2000,NULL);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
UINT CDlgInfo::ScanThread( LPVOID pParam)
{
CDlgInfo *pDlg=(CDlgInfo *)pParam;
//创建一个CSingleLock对象,初始化为信号量sem
CSingleLock singlock(pDlg->sem);
//当前还未刷新界面
pDlg->m_bRefreshFlag=FALSE;
do
{
//锁信号量
singlock.Lock();
//发送snmp包到底层
pDlg->SendSnmp(); //当前设备有电,并且当前还未刷新界面,则开启定时器13,没隔100ms刷新一次
if((pDlg->m_bPowerFlag==TRUE)&&(pDlg->m_bRefreshFlag==FALSE))
{
pDlg->m_bRefreshFlag=TRUE;//已经开启定时器刷新界面了,不需要再次开启了
pDlg->SetTimer(13,100,NULL);
}
//开信号量
singlock.Unlock();
//休眠1000ms
Sleep(1000);
}
while(pDlg->m_bPowerFlag==TRUE);//当前设备还有电,则继续扫描 pDlg->KillTimer(13);//线程即将退出,将刷新界面定时器关掉,不再刷新界面了
return 0;
}
解决方案 »
- 驱动中 和hid 小端口设备通讯的问题
- Document类能不能用在任意窗口中?
- 疑难杂症啊.程序退出时弹出出错对话框(内存越界),来者有其分,解决了可再加.
- 目前遭遇数据库性能无法提高写库速度,寻求解决方案?
- 弱弱的问,在只用ATL做的控件中如何弹出popup menu啊?我的方法不行
- 十分郁闷的窗口拆分问题!!!
- how open *.sit?
- 如何在程序中监测并阻止用户修改系统时间?
- 在UAC和IE的保护模式下,嵌入网页的OCX到底哪些不能做了?
- MFC无法添加ActiveX控件的类向导!求助!
- 显示文件内容。急......
- 请问:将窗口分割成4块之后,初始化的时候在屏幕如何平均分4个子窗口(2行2列)??
{
// TODO: Add your message handler code here and/or call default
switch (nIDEvent)
{
case 11:
if(pScanThread==NULL)//第一次启动
{
pScanThread=AfxBeginThread(ScanThread,this);//启动线程
pScanThread->m_bAutoDelete=FALSE;//线程为手动删除
}
//当前线程没有启动或已结束,则启动当前线程
else if(WaitForSingleObject(pScanThread->m_hThread,0)==WAIT_OBJECT_0)
{
KillTimer(11);
//删除先前线程的资源
if(pScanThread!=NULL)
{
delete pScanThread;//删除线程
pScanThread=NULL;
}
//启动线程
pScanThread=AfxBeginThread(ScanThread,this);
pScanThread->m_bAutoDelete=FALSE;//线程为手动删除
SetTimer(11,2000,NULL);
}
case 12://一次查询结束
//查询机架信息时超时,则表示设备没电了
if(m_bJijiaFlag==TRUE)
m_bPowerFlag=FALSE;
KillTimer(12);
m_bReceived=TRUE;
break;
case 13:
//不断地刷新界面
//m_bFlashFlag=!m_bFlashFlag;
InvalidateRect(CRect(0,50,ptRect[16].right,ptRect[16].bottom),FALSE);
}
CDialog::OnTimer(nIDEvent);
} void CDlgInfo::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
//在这里画图(画在对话框上,根据从底层获取的数据的不同,画的内容也不同)
}void CDlgInfo::SendSnmp()
{ int i;
//查询底层信息
m_bJijiaFlag=TRUE;//当前正在查询机架
/**********这里是发送snmp包到底层,当底层收到数据之后,接着立刻返回相应的数据,
在我程序里是通过 recv消息的接收函数OnRecv来实现的*************/
if(pSnmp.sessionID==FALSE)
{
pSnmp.CreateSession(m_hWnd,wMsg);
pSnmp.sessionID=TRUE;
}
pSnmp.CreateVbl("1.3.6.1.4.1.991.1.1.0",NULL);
pSnmp.SetVbl("1.3.6.1.4.1.991.1.2.0",NULL);
pSnmp.SetVbl("1.3.6.1.4.1.991.1.3.0",NULL);
pSnmp.SetVbl("1.3.6.1.4.1.991.1.4.0",NULL);
pSnmp.CreatePdu(SNMP_PDU_GET,NULL,NULL,NULL);
pSnmp.Send(m_sIP,"public");
/******snmp发送完毕*****/ //发送后等待一段时间,等待接收数据
SendDelay(100);
m_bJijiaFlag=FALSE;//机架信息查询完毕
}
void CDlgInfo::SendDelay(int delaytime)
{
//设置当前还未收到底层的数据
m_bReceived=FALSE;
//设置12号定时器来使当时间过了200ms还未收到数据后,使m_bReceived变为真,以便下一轮的发送
KillTimer(12);
SetTimer(12,delaytime,NULL);
MSG message; /*等待收取数据,如果数据还未收到,则等待,(过了200ms后还未收到数据后,
12号定时器,会强制使数据接收标志置为真,从而退出循环,准备下一轮发送
)在这里表现为转发消息*/
while(m_bReceived==FALSE)
{
if(::PeekMessage(&message,NULL,0,0,PM_REMOVE))
{
::TranslateMessage(&message);
::DispatchMessage(&message);
}
}
}void CDlgInfo::OnRecv(WPARAM wParam, LPARAM lParam)
{ CString strIp;
CString strTemp;
int nIpin=0;//保存接收的整数值
CString str="";//保存接收的字符串
pSnmp.Receive(m_sOid,m_value); if(pSnmp.nCount>0)//收到了数据包
{
m_bPowerFlag=TRUE;
Module[16].m_bPowerFlag=TRUE; for(int i=0;i<pSnmp.nCount;i++)
{
//接收数据
switch(m_value[i]->syntax)
{
case SNMP_SYNTAX_INT:
//case SNMP_SYNTAX_INT32:
smiINT sNumber;
sNumber=m_value[i]->value.sNumber;
nIpin=sNumber;
str.Format("%d",sNumber); break;
//省略若干
}
//分析数据,并将数据存放到相应的地方去(存放到相应的数组中) }
//接收数据标志位置为真
m_bReceived=TRUE;
//关闭12号定时器,不需要判断数据包接收超时了
KillTimer(12);
}
} void CDlgInfo::OnDestory()
{
//关闭所有的定时器
KillTimer(11);
KillTimer(12);
KillTimer(13); if(pScanThread!=NULL)
while (TRUE)
{
DWORD result;
MSG msg ;
m_bPowerFlag=FALSE;//改变变量,等待线程结束
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
}
//判断线程是否结束,如果还未结束,则等待并转发消息,否则就退出程序了
result = MsgWaitForMultipleObjects(1, &pScanThread->m_hThread,
FALSE, INFINITE, QS_ALLINPUT);
if (result == (WAIT_OBJECT_0 + 1))
{
::MessageBox(NULL, "STOP","结束线程not!",MB_OK);
continue;
}
else
{
::MessageBox(NULL, "STOP","成功结束线程!",MB_OK);
break;
}
}
//删除线程资源
if(pScanThread!=NULL)
{
delete pScanThread;//删除线程
pScanThread=NULL;
}
}
如果可以的话 [email protected]
没事关掉ScanThread干什么,一直开着好了,用WaitForSingleObject或Sleep来代替你的定时器吧,工作线程里Sleep不会影响你的主线程的
在你的ScanThread里
while(true){
breceived = false;
powerflag = false;
while(!breceived){
SendSnmp();
Sleep(100);
RecvSnmp();//收到的话breceived=true;powerflag=true;而且发送后就可以刷新了啊,为什么要用定//时器呢,不过用了也没关系!
}
if(!powerflag)Sleep(2000);
else{
//设置刷新定时器,如果需要的话
}
}
其次,我刷新界面的屏幕要比你取完数据后再刷新的频率快,这主要是为了能让屏幕上某些灯能够一直在闪烁,如果采用在取完数据在刷新界面的画,就没有那种效果了,因为速度太满了
刷新界面比取数据快,那不是说,你刷新所用的数据有可能是相同的,就我所知OnTimer本身精度才55ms,也快不了多少的
那么你的2s的定时器,是不是有点多余了,你的ScanThread为什么要退出呢,每过1000ms判断是否有电,有电就发送数据,没电就不发好了,我甚至看不出你将ScanThread做成一个线程的必要性,弄个1000ms的定时器不就好了
原来就是这样做的,但那样更新的速度太慢了,耗用cpu资源太多了,才把它改成多线程的,还请各位多帮帮忙,看看,改改