论文导读:下面以VisualC++{以下简称VC++)为例,说明采用多线程的处理方式。
关键词:VC++,实时数据,采集
1.问题的提出
随着自动化水平的日益提高,许多工业过程控制都采用了二级或多级计算机系统进行处理。在这些控制场合中,DDC一般都有串行口,通过它们可以方便地进行数据传输,上位机采用面向对象的语言,设计一个友好的人机界面,这样一来,我们就可以很方便的在控制室的计算机上对现场数据进行监控,可随时统计生产数据,动态显示、存储和输出生产报表等。对于这样一个有着非常友好人机界面的系统,如果它以图形、图像的方式来显示设备的状况,那么系统要花相当的CPU时间去处理这一部分。特别对于实时系统或采样频率较高、每帧数据量又很大的系统,若采用单线程处理,系统的响应时间,屏幕的刷新时间都会增加,导致系统性能降低。但是如果采用多线程方式处理,效果就会好得多。发表论文。发表论文。下面以Visual C++{以下简称VC++)为例,说明采用多线程的处理方式。
2.系统的设计实施
在VC++中,开发串行通信主要有以下四种方式:
(1)用V C++提供的串行口通信控件M5Comm,它简单易用,但不灵活;
(2)用单线程的方法实现自定义串口通信类(封装API),它比MSComm要简单,可用于简单系统;
(3)用多线程的方法实现自定义串行通信类,这种方法较灵活,且CPU利用率高;
(4)直接读写串行口(自己编写驱动程序),这需要编写大量的底层软件,较复杂。
在我们的系统中采用了多线程方式,DDC不断地将数据传送给上位机,上位计算机采用被动接收数据的方式,主线程用来处理现场数据的统计、数据的存储与输出,以及用户界面的消息处理。此外,再设两个线程,线程1(RxThreadFunc)用来监视串行口,采集数据并将数据存放到一个环形缓冲区中。线程2 (Handle ThreadFunc)用来从环形缓冲区中取数据进行动态显示和保存数据。系统首先对两个线程进行说明,然后创建它们,具体过程如下:
在头文件中说明。发表论文。
static UINT RxThreadFunc(LPVOID);
static UINT Handle ThreadFunc(LPVOID);
程序初始化时可加入如下代码创建线程。
CWin Thread*_p RxThread;
CWin Thread*_p Handle Thread;
_pRxThread=AfxBeginThread
(RxThreadFunc,NULL,THREAD_PRIORITY_NORMAL,0,0,//Start the thread immediately after creation
NULL);
_pHandle Thread= AfxBeginThread
(Handle ThreadFunc,NULL,TH READ_PRIORITY_NORMAL,0,0,//Start the thread immediately after creation
NULL);
这样创建后,这种两个线程就可以和主线程并发执行了,设备数据显示的动态刷新和用户界面消息的处理也就可以独立的运行。AfxBeginThread各参数的含义可参考微软的MSDN。主线程及线程2 (Handle ThreadFunc)与一般的编程处理并无二样,所以下面着重说明接收数据线程(RxThreadFunc )。
首先生成一个串行口操作类,串行口类构造函数如下:
CCommunication::CCommunication ( ){ m_hComm=NULL;
m_bOpened=false;
BaudRate=CBR_9600;
ByteSize=8;
fParity=FALSE;
Parity=NOPARITY;
StopBits=ONESTOPBIT;}
它的读操作如下:
Int CCommunication::CComRead (LPVOID pData,intn nLen){
DWORD dwBytesRead;
DWORD dwError;
COMSTAT ComStat;
if(m_hComm==NULL) return-1;
if(!ReadFile(mhComm,(LPVOID)pData,nLen,&dwBytesRead,NULL)){
dwError=GetLastError( );
}
If(dwBytesRead((DWORD)nLen)
ClearCommError (m_hComm,&dwError, &ComStat);
return dwBytesRead;
}
接收线程程序如下(在启动线程之前应先打开串口):
CCommunication vSerialPort;
UINTRxThreadFunc(LPVOID ThreadArg)
{
DWORD dwArg=*(DWORD*)ThreadArg;
unsigned char temparr[10];
while(1) {
if( vSerialPort.ComRead(&emparr,l)>0) {//也可读入多个字节
vCircBuf.AddItem s (&temparr,1) ;//存入缓冲区中
}
else{
Sleep(0) :
}
}
return 0 ;
}
程序中vCircBuf为对缓冲区操作类,此缓冲区为临界资源,应互斥使用。当然程序在此也可对读入的数据进行其他方式的处理。
3.结束语
我们用一个RxThreadFunc( LPVOIDThreadArg)工作线程在后台单独接收数据,保证了实时接收数据的不丢失,减少了用户界面消息处理的响应时间,提高了系统的性能。
参考文献:
[1]李于剑.VisualC++实践与提高.中国铁道出版社,2001.
[2]官章全,唐晓卫.Visual C++6.0编程实例详解.电子工业出版社,2000.
|