多线程编程基础知识(一)

当前流行的Windows操作系统能同时运行几个程序(独立运行的程序又称为进程),对于同一个程序,它又可以分为若干个独立的执行流,我们称之为线程,线程提供了多任务处理的能力。用线程和进程的观点来研究软件是当今普遍采用的方法,进程和线程的概念的出现,对提高软件的并行性有着重要的意义。现在的大型应用软件无一不是多线程多任务处理,单线程的软件是不可想象的。因此掌握多线程多任务设计方法对每个程序员都是必需要掌握的。本实例针对多线程技术在应用中经常遇到的问题,如线程间的通信、同步等,分别进行探讨,并利用多线程技术进行线程之间的通信,实现了数字的简单排序。

一、实现方法

1.理解线程

要讲解线程,不得不说一下进程,进程是应用程序执行的实例,每个进程是由私有的虚拟地址空间、代码、数据和其他系统资源组成。进程在运行时创建的资源随着进程的终止而死亡。线程的基本思想很简单,它是一个独立的执行流,是进程内部的一个独立的执行单元,相当于一个子程序,它对应于Visual C++中的CWinMain类对象。单独一个执行程序运行时,缺省地包含的一个主线程,主线程以函数地址的形式出现,提供程序的启动点,如main()或WinMain()函数等。当主线程终止时,进程也随之终止。根据实际需要,应用程序可以分解成许多独立执行的线程,每个线程并行的运行在同一进程中。

一个进程的所有线程都在该进程的虚拟地址空间中,使用该进程的全局变量和系统资源。操作系统给每个线程分配不同的CPU时间片,在某一个时刻,CPU只执行一个时间片内的线程,多个时间片中的相应线程在CPU中轮流执行,由于每个时间片时间很短,所以对用户来说,仿佛各个进程在计算机中是并行处理的。操作系统是根据线程的优先级来安排CPU时间,优先级高的线程优先运行,优先级低的线程则继续等待。

线程被分为两种:用户界面线程和工作线程(又称为后台线程)。用户界面线程通常用来处理用户的输入并响应各种事件和消息,其实,应用程序的主执行线程CWinAPP对象就是一个用户 界面线程,当应用程序启动时自动创建和启动,同样它的终止也意味着该程序的结束,进程终止。工作线程用来执行程序的后台处理任务,比如计算、调度、对串口的读写操作等,它和用户界面程序的区别是它不用从CWinThread类派生来创建,对它来说最重要的是如何实现工作线程任务的运行控制函数。工作线程和用户界面线程启动时要调用同一个函数的不同版本;最后需要明白的是,一个进程中的所有线程可以共享他们父进程的变量,但同时每个进程可以拥有自己的变量。

2、线程的管理和操作

(一)线程的启动

创建一个用户界面线程,首先要从类CWinThread产生一个派生类,同时必须使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE来声明和实现这个CWinThread派生类。
第二步是根据需要重载该派生类的一些成员函数如:ExitIntstance()、InitInstance()、OnIdle()、PreTranslateMessage()等函数。
最后调用AfxBeginThread()函数的一个版本:CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL ) 启动该用户界面线程,其中第一个参数为指向定义的用户界面线程类指针变量,第二个参数为线程的优先级,第三个参数为线程所对应的堆栈大小,第四个参数为创建线程时的附加标志,缺省为正常状态,如为CREATE_SUSPENDED则线程启动后为挂起状态。

对于工作线程来说,启动一个线程,首先需要编写一个希望与应用程序的其余部分并行运行的函数如Fun1(),接着定义一个指向CwinThread对象的指针变量*pThread,调用AfxBeginThread( Fun1, param, priority) 函数,返回值赋给pThread变量的同时一并启动该线程来执行上面的Fun1()函数,其中Fun1是线程要运行的函数的名字,也就是上面所说的控制函数的名字,param是准备传送给线程函数Fun1的任意32位值,priority则是定义该函数的优先级别,它是预定义的常数,可参考MSDN。

(二)线程的优先级

以下是CWinThread类的成员函数用于线程优先级的操作:

int GetThreadPriority();
BOOL SetThradPriority()(int nPriority);

上述两个函数分别用来获取和设置线程的优先级,这里的优先级,是相对于该线程所处的优先权层次而言的,处于同一优先权层次的线程,优先级高的线程先运行;处于不同优先权层次上的线程,谁的优先权层次高,谁先运行。至于优先级设置所需的常数,参考MSDN,要注意的是要想设置线程的优先级,这个线程在创建时必须具有THREAD_SET_INFORMATION访问权限。对于线程的优先权层次的设置,CWinThread类并没有提供相应的函数,但是可以通过Win32SDK函数GetPriorityClass()和SetPriorityClass() 来实现。

(三)线程的悬挂和恢复

CWinThread类中包含了应用程序悬挂和恢复它所创建的线程的函数,其中SuspendThread() 用来悬挂线程,暂停线程的执行;ResumeThread() 用来恢复线程的执行。如果你对一个线程连续若干次执行SuspendThread() ,则需要连续执行相应次的ResumeThread()来恢复线程的运行。

(四)结束线程

终止线程有三种途径,线程可以在自身内部调用AfxEndThread()来终止自身的运行;
可以在线程外部调用BOOL TerminateThread(HANDLE和Tread, DWORD dwExitCode)来强制终止一个线程的运行,然后调用CloseHandle() 函数释放线程所占用的堆栈;
第三种方法是改变全局变量,使线程的执行函数返回,则该线程终止。下面以第三种方法为例,给出部分代码:

/CtestView message handlers
/Set to True to end thread
Bool bend = FALSE;//定义全局变量,用于控制线程的运行;
//The Thread Function;
UINT TheaadFunction(LPVOID pParam)//线程函数
{
while (!bend)
{
Beep(100, 100);
Sleep(1000);
}
return 0;
}

CwinThread*pThread;
HWND hWnd;
Void CtestView::OnintialUpdate()
{
hWnd =GetSafeHwnd();
pThread=AfxBeginThread(ThradFunction,hWnd);//启动线程
pThread->m_bAutoDelete=FALSE;//线程为手动删除
Cview::OnInitialUpdate();
}

Void CtestView::OnDestroy()
{
bend=TRUE;//改变变量,线程结束
WaitForSingleObject(pThread->m_hThread,INFINITE);//等等线程结束
delete pThread;//删除线程
Cview::OnDestroy();
}

3、线程之间的通信
……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值