多线程技术在VC中的应用
【打印文章】
山东理工大学 贾永新 肖爱梅
Visual C++ 6.0 自发布以来,以其强大的功能及各种新特性受到广大编程爱好者的青睐。但是要想成为一个优秀的程序员,写出真正功能强大、能够快速响应且实用的程序就必须充分利用一项关键技术:多线程。笔者在工作中应用这一技术,开发了一个定时关机的实用程序,在此介绍给广大读者,借此帮助读者加深对这一技术的理解。
程序的功能
此实用程序的主要功能是实现定时关机,同时也提供了辅助功能:随时关机、重新启动、注销以及动态时钟。如果设置的时间不对,可以随时更改。这些功能的具体实现采用了多线程技术。
功能的实现
1.线程的定义
本例中单独设置了一个线程监视当前时间,在Visual C++中线程的简单调用语句为:AfxBegin
-Thread(ProcName, param, Priority),第一个参数是线程函数名,param是准备传送给线程的任意32位值,最后一个是线程的优先级(可用常量表示)。这里先定义一个线程函数:
UINT timeThreadProc(LPVOID pParam) //定义线程,必须照此格式
{
CTime gt; //定义时间变量
int hh,mm,ss; //为存储时间定义整型变量
do //判断时间的循环
{
gt=CTime::GetCurrentTime();
//提取当前时间
hh=gt.GetHour(); //分别提取时、分、秒 mm=gt.GetMinute();
ss=gt.GetSecond();
} while ((h!=hh)||(m!=mm)||(s!=ss));
//判断当前时间
flag=0; //置状态标志
ExitWindowsEx(EWX_SHUTDOWN,0);
//关闭计算机
return 0;
}
在上面这个函数中,第一行的格式不能改变,其中的h、m、s是三个全局变量,存储的是设定的时间(时、分、秒)值。通过循环判断,如果当前时间满足设定的条件,则调用MFC的函数ExitWindowsEx(UNIT uFlags, DWORD dwReserved)来关闭计算机。
2.线程的调用
线程的调用方式为:CWinThread * pThread=AfxBeginThread(ProcName,param,Priority),其中pThread是指向该线程的指针。源代码及说明如下:
void CShutDlg::Onqd()
//设置时间后的响应函数
{
UpdateData(TRUE); //从对话框取值
h=m_xsh; //把时、分、秒值传给全局变量
m=m_fzh;
s=m_miao;
if (flag==1) {pThread->ResumeThread();}
//通过状态标志判断,如果线程已经启动,则恢复运行
else {
pThread=AfxBeginThread(timeThreadProc,GetSafeHwnd(),THREAD_PRIORITY_NORMAL); //如果线程没运行,则启动线程
flag=1;} //把线程状态标志位置1
m_chsh.EnableWindow(1);
//重设按钮可用
m_qd.EnableWindow(0);
//设定按钮不可用
}
点击“重设”按钮的响应函数:
void CShutDlg::Onchsh()
{
if(flag==1) //判断标志位
{
pThread->SuspendThread();
//如果线程已经启动,则挂起
}
m_chsh.EnableWindow(0);
//重设按钮不可用
m_qd.EnableWindow(1); //设定按钮可用
}
在启动线程的时候,用*pThread保存线程的指针使得我们可以对线程进行挂起(SuspendThread函数)、恢复(ResumeThread函数)等操作,并通过全局变量h、m、s与线程通信,达到定时关机的目的。
3.动态时钟线程的实现
为了方便定时,在此程序中加入了一个时钟。原理主要是通过一个定时器(Timer),定时读取当前时间并按照格式显示,这里涉及到了VC中的另一个重要函数:OnTimer(UINT nIDEvent)。在程序启动初始化的时候,加入语句: m_nTimer=SetTimer(1,100,NULL),其中参数100是响应周期(ms)。通过向导加入时间响应函数,代码如下:
void CShutDlg::OnTimer(UINT nIDEvent) //定时器响应函数
{
CTime gg; //定义时间变量
CString s;
gg=CTime::GetCurrentTime();
//取出当前时间
s.Format(“%02d”,gg.GetSecond());
//定义输出格式
SetDlgItemText(IDC_miao1,s);
//在程序中显示时间
s.Format(“%02d”,gg.GetHour());
SetDlgItemText(IDC_xsh1,s);
s.Format(“%02d”,gg.GetMinute());
SetDlgItemText(IDC_fzh1,s);
CDialog::OnTimer(nIDEvent);
}
OnTimer(UINT nIDEvent)是系统函数,它参考初始化时设置的响应周期(100ms)来执行。需要注意的是,如果在程序中设置了Timer,那么在程序结束的时候要加上语句:KillTimer(0),以销毁定时器对象,否则白白浪费系统资源。
至此一个较为完整的定时器程序完成(其中重启、注销功能的实现很简单,也非本文的主题,故略过),如果再添加几个线程,即可扩展为一个多功能备忘录,有兴趣的读者可以加以改进。
小 结
本文中只是简单地运用了一个线程,控制方式也是简单地与全局变量通信的方法,在实际应用中还要注意线程同步、线程之间通信、线程与进程之间通信、利用全局变量通信、利用用户定义消息通信、利用事件通信等等许多重要问题。只有真正掌握了多线程高级编程技术才能写出实用、优秀的程序。
Visual C++ 6.0 自发布以来,以其强大的功能及各种新特性受到广大编程爱好者的青睐。但是要想成为一个优秀的程序员,写出真正功能强大、能够快速响应且实用的程序就必须充分利用一项关键技术:多线程。笔者在工作中应用这一技术,开发了一个定时关机的实用程序,在此介绍给广大读者,借此帮助读者加深对这一技术的理解。
程序的功能
此实用程序的主要功能是实现定时关机,同时也提供了辅助功能:随时关机、重新启动、注销以及动态时钟。如果设置的时间不对,可以随时更改。这些功能的具体实现采用了多线程技术。
功能的实现
1.线程的定义
本例中单独设置了一个线程监视当前时间,在Visual C++中线程的简单调用语句为:AfxBegin
-Thread(ProcName, param, Priority),第一个参数是线程函数名,param是准备传送给线程的任意32位值,最后一个是线程的优先级(可用常量表示)。这里先定义一个线程函数:
UINT timeThreadProc(LPVOID pParam) //定义线程,必须照此格式
{
CTime gt; //定义时间变量
int hh,mm,ss; //为存储时间定义整型变量
do //判断时间的循环
{
gt=CTime::GetCurrentTime();
//提取当前时间
hh=gt.GetHour(); //分别提取时、分、秒 mm=gt.GetMinute();
ss=gt.GetSecond();
} while ((h!=hh)||(m!=mm)||(s!=ss));
//判断当前时间
flag=0; //置状态标志
ExitWindowsEx(EWX_SHUTDOWN,0);
//关闭计算机
return 0;
}
在上面这个函数中,第一行的格式不能改变,其中的h、m、s是三个全局变量,存储的是设定的时间(时、分、秒)值。通过循环判断,如果当前时间满足设定的条件,则调用MFC的函数ExitWindowsEx(UNIT uFlags, DWORD dwReserved)来关闭计算机。
2.线程的调用
线程的调用方式为:CWinThread * pThread=AfxBeginThread(ProcName,param,Priority),其中pThread是指向该线程的指针。源代码及说明如下:
void CShutDlg::Onqd()
//设置时间后的响应函数
{
UpdateData(TRUE); //从对话框取值
h=m_xsh; //把时、分、秒值传给全局变量
m=m_fzh;
s=m_miao;
if (flag==1) {pThread->ResumeThread();}
//通过状态标志判断,如果线程已经启动,则恢复运行
else {
pThread=AfxBeginThread(timeThreadProc,GetSafeHwnd(),THREAD_PRIORITY_NORMAL); //如果线程没运行,则启动线程
flag=1;} //把线程状态标志位置1
m_chsh.EnableWindow(1);
//重设按钮可用
m_qd.EnableWindow(0);
//设定按钮不可用
}
点击“重设”按钮的响应函数:
void CShutDlg::Onchsh()
{
if(flag==1) //判断标志位
{
pThread->SuspendThread();
//如果线程已经启动,则挂起
}
m_chsh.EnableWindow(0);
//重设按钮不可用
m_qd.EnableWindow(1); //设定按钮可用
}
在启动线程的时候,用*pThread保存线程的指针使得我们可以对线程进行挂起(SuspendThread函数)、恢复(ResumeThread函数)等操作,并通过全局变量h、m、s与线程通信,达到定时关机的目的。
3.动态时钟线程的实现
为了方便定时,在此程序中加入了一个时钟。原理主要是通过一个定时器(Timer),定时读取当前时间并按照格式显示,这里涉及到了VC中的另一个重要函数:OnTimer(UINT nIDEvent)。在程序启动初始化的时候,加入语句: m_nTimer=SetTimer(1,100,NULL),其中参数100是响应周期(ms)。通过向导加入时间响应函数,代码如下:
void CShutDlg::OnTimer(UINT nIDEvent) //定时器响应函数
{
CTime gg; //定义时间变量
CString s;
gg=CTime::GetCurrentTime();
//取出当前时间
s.Format(“%02d”,gg.GetSecond());
//定义输出格式
SetDlgItemText(IDC_miao1,s);
//在程序中显示时间
s.Format(“%02d”,gg.GetHour());
SetDlgItemText(IDC_xsh1,s);
s.Format(“%02d”,gg.GetMinute());
SetDlgItemText(IDC_fzh1,s);
CDialog::OnTimer(nIDEvent);
}
OnTimer(UINT nIDEvent)是系统函数,它参考初始化时设置的响应周期(100ms)来执行。需要注意的是,如果在程序中设置了Timer,那么在程序结束的时候要加上语句:KillTimer(0),以销毁定时器对象,否则白白浪费系统资源。
至此一个较为完整的定时器程序完成(其中重启、注销功能的实现很简单,也非本文的主题,故略过),如果再添加几个线程,即可扩展为一个多功能备忘录,有兴趣的读者可以加以改进。
小 结
本文中只是简单地运用了一个线程,控制方式也是简单地与全局变量通信的方法,在实际应用中还要注意线程同步、线程之间通信、线程与进程之间通信、利用全局变量通信、利用用户定义消息通信、利用事件通信等等许多重要问题。只有真正掌握了多线程高级编程技术才能写出实用、优秀的程序。
本栏文章均来自于互联网,版权归原作者和各发布网站所有,本站收集这些文章仅供学习参考之用。任何人都不能将这些文章用于商业或者其他目的。( Pfan.cn )
【编程爱好者论坛】