没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
多线程编程
一、问题的提出
编写一个耗时的单线程程序:
新建一个基于对话框的应用程序 SingleThread,在主对话框
IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为 IDC_SLEEP_SIX_SECOND,标题
为“延时 6秒”,添加按钮的响应函数,代码如下:
void CSingleThreadDlg::OnSleepSixSecond()
{
Sleep(6000); //延时 6秒
}
编译并运行应用程序,单击“延时 6 秒”按钮,你就会发现在这 6 秒期间程序就象“死机”
一样,不在响应其它消息。为了更好地处理这种耗时的操作,我们有必要学习——多线程编
程。
二、多线程概述
进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是
由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程
中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放
或关闭。
线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了
该进程的主执行线程,主执行线程以函数地址形式,比如说 main或 WinMain函
数,将程序的启动点提供给 Windows系统。主执行线程终止了,进程也就随之终
止。
每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自
动创建的。用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同
一个进程中。一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这
些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技
术的应用也较为广泛。
多线程可以实现并行处理,避免了某项任务长时间占用 CPU时间。要说明的
一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,
操作系统为每个独立线程安排一些 CPU时间,操作系统以轮换方式向线程提供时
间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果两个非
常活跃的线程为了抢夺对 CPU的控制权,在线程切换时会消耗很多的 CPU资源,
反而会降低系统的性能。这一点在多线程编程时应该注意。
Win32 SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各
种同步、互斥和临界区等操作。Visual C++ 6.0中,使用 MFC类库也实现了多
线程的程序设计,使得多线程编程更加方便。
三、Win32 API对多线程编程的支持
Win32 提供了一系列的 API函数来完成线程的创建、挂起、恢复、终结以及
通信等工作。下面将选取其中的一些重要函数进行说明。
1、HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄,其中各参数
说明如下:
•
lpThreadAttributes:指向一个 SECURITY_ATTRIBUTES 结构的指针,该结构决定了线
程的安全属性,一般置为 NULL;
•
dwStackSize:指定了线程的堆栈深度,一般都设置为 0;
•
lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。
一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是线程函数名;
• lpParameter:指定了线程执行时传送给线程的 32 位参数,即线程函数的参数;
•
dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为 0,线程
在被创建后就会立即开始执行;如果该参数为 CREATE_SUSPENDED,则系统产生线程
后,该线程处于挂起状态,并不马上执行,直至函数 ResumeThread 被调用;
•
lpThreadId:该参数返回所创建线程的 ID;
如果创建成功则返回线程的句柄,否则返回 NULL。
2、DWORD SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。
3、DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态,执行线程。
4、VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数 dwExitCode
用来设置线程的退出码。
5、BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用
TerminateThread 强行终止某一线程的执行。各参数含义如下:
•
hThread:将被终结的线程的句柄;
•
dwExitCode:用于指定线程的退出码。
使用 TerminateThread()终止某个线程的执行是不安全的,可能会引起系统
不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源。因此,
一般不建议使用该函数。
6、BOOL PostThreadMessage(DWORD idThread,
UINT Msg,
WPARAM wParam,
LPARAM lParam);
该函数将一条消息放入到指定线程的消息队列中,并且不等到消息被该线程处理时便返回。
•
idThread:将接收消息的线程的 ID;
•
Msg:指定用来发送的消息;
•
wParam:同消息有关的字参数;
•
lParam:同消息有关的长参数;
调用该函数时,如果即将接收消息的线程没有创建消息循环,则该函数执行失败。
四、Win32 API多线程编程例程
例程 1 MultiThread1
1. 建立一个基于对话框的工程 MultiThread1,在对话框 IDD_MULTITHREAD1_DIALOG 中
加入两个按钮和一个编辑框,两个按钮的 ID 分别是 IDC_START,IDC_STOP ,标题分
别为“启动”,“停止”,IDC_STOP 的属性选中 Disabled;编辑框的 ID 为 IDC_TIME ,
属性选中 Read-only;
2. 在 MultiThread1Dlg.h 文件中添加线程函数声明:
void ThreadFunc();
注意,线程函数的声明应在类 CMultiThread1Dlg 的外部。 在类 CMultiThread1Dlg 内
部添加 protected 型变量:
HANDLE hThread;
DWORD ThreadID;
分别代表线程的句柄和 ID。
3. 在 MultiThread1Dlg.cpp 文件中添加全局变量 m_bRun :
volatile BOOL m_bRun;
m_bRun 代表线程是否正在运行。
你要留意到全局变量 m_bRun 是使用 volatile 修饰符的,volatile 修饰符的作用是
告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值
可被外部改变。对于多线程引用的全局变量来说,volatile 是一个非常重要的修饰符。
编写线程函数:
void ThreadFunc()
{
CTime time;
CString strTime;
m_bRun=TRUE;
while(m_bRun)
{
time=CTime::GetCurrentTime();
strTime=time.Format("%H:%M:%S");
::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_TIME,strTime);
Sleep(1000);
}
}
该线程函数没有参数,也不返回函数值。只要 m_bRun 为 TRUE,线程一直运行。
双击 IDC_START 按钮,完成该按钮的消息函数:
void CMultiThread1Dlg::OnStart()
{
// TODO: Add your control notification handler code here
hThread=CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadFunc,
NULL,
0,
&ThreadID);
GetDlgItem(IDC_START)->EnableWindow(FALSE);
GetDlgItem(IDC_STOP)->EnableWindow(TRUE);
}
双击 IDC_STOP 按钮,完成该按钮的消息函数:
void CMultiThread1Dlg::OnStop()
{
// TODO: Add your control notification handler code here
m_bRun=FALSE;
GetDlgItem(IDC_START)->EnableWindow(TRUE);
GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
}
编译并运行该例程,体会使用 Win32 API 编写的多线程。
例程 2 MultiThread2
该线程演示了如何传送一个一个整型的参数到一个线程中,以及如何等待一
个线程完成处理。
1. 建立一个基于对话框的工程 MultiThread2,在对话框 IDD_MULTITHREAD2_DIALOG 中
加入一个编辑框和一个按钮,ID 分别是 IDC_COUNT,IDC_START ,按钮控件的标题
为“开始”;
2. 在 MultiThread2Dlg.h 文件中添加线程函数声明:
void ThreadFunc(int integer);
注意,线程函数的声明应在类 CMultiThread2Dlg 的外部。
在类 CMultiThread2Dlg 内部添加 protected 型变量:
HANDLE hThread;
DWORD ThreadID;
分别代表线程的句柄和 ID。
3. 打开 ClassWizard,为编辑框 IDC_COUNT 添加 int 型变量 m_nCount。在
MultiThread2Dlg.cpp 文件中添加:
4. void ThreadFunc(int integer)
5. {
6. int i;
7. for(i=0;i<integer;i++)
8. {
9. Beep(200,50);
10. Sleep(1000);
11. }
}
双击 IDC_START 按钮,完成该按钮的消息函数:
void CMultiThread2Dlg::OnStart()
{
UpdateData(TRUE);
int integer=m_nCount;
hThread=CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadFunc,
(VOID*)integer,
0,
&ThreadID);
GetDlgItem(IDC_START)->EnableWindow(FALSE);
剩余28页未读,继续阅读
资源评论
- guchengfeixue2012-12-05不错,讲得很详细,可以好好学一下
lzl32163
- 粉丝: 13
- 资源: 54
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功