码迷,mamicode.com
首页 > 编程语言 > 详细

第6章 线程基础

时间:2015-08-03 00:59:04      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:

6.1 线程基础

(1)线程组成:线程内核对象+线程栈(注意:进程=进程内核对象+地址空间

  ①从内核角度看,线程是一个内核对象,系统用它来存储一些关于线程的统计信息(比如运行时间等)

  ②从编程角度看,线程是一堆寄存器状态以及线程栈的一个结构体对象。本质上可以理解为一个函数的调用器(其中的寄存器状态用于控制CPU执行,栈用于存储局部变量和函数参数及函数的返回地址)——为什么要使用线程栈的?

线程1

线程2

备注(使用线程栈的原因分析)

void func1(){

  int a;

  int b;

}

void func2(){

  int c;

  int d;

}

如果不为每个线程分配线程栈,而使用进程中某一共同的栈,设func3先于func4执行,则变量进栈顺序a、b,如果此时执行线程2,则c、d也会进栈,栈顶指针指向d。假设这时func3执行完,要回收栈则会出现将c、d弹出栈的错误。现实中可能会出现更复杂的情况。当然,如果这两个线程严格串行执行,则不会出现这种错误。

  ③线程还可以带有消息队列(GUI线程内部会创建)和APC队列。(但注意这些队列在线程创建时并不同时创建,要在调用GUI函数里才会被创建!)

★进程是线程的容器,线程共享进程的地址空间和资源

(2)什么时候不使用多线程

  ①当一个算法本身是严格串行化的时候,即计算的每一步都严重依赖前一个操作步骤的结果时,不适合用多线程)。

  ②当多个功能任务具有比较严格的先后逻辑关系时,不宜采用多线程。因为这涉及到线程同步方法的严格控制,从而可能因加了过多的同步而降低了效率。

  ③还有一种特殊情况,比如一个服务器需要处理成千上万个客户端连接,不宜使用多线程,因为过多的线程间的切换也会降低效率,这里可以考虑用线程池

6.2 主线程

(1)进程的入口函数,从本质上看就是主线程的入口函数。在C\C++下是WinMainCRTStartup

(2)主线程是进程内第1个可执行的线程实体,它可以用来创建别的线程。

(3)主线程退出后,进程也会退出(因为VS嵌入的入口函数会调用ExitProcess终止其它线程的执行。(当自定义入口时,这个行为就要在自定义的入口函数中自行的维护,即自定义入口函数时,那么进程将在最后一个线程退出后,才退出。因此,主线程也未必是最后一个线程!)。

6.3 线程函数(也叫线程入口函数)

(1)线程函数的原型:DWORD WINAPI ThreadProc(LPVOID lpParameter);

(2)线程函数是线程执行的起点,可以执行我们希望的任何任务

(3)当线程函数执行完毕,线程将退出,同进线程栈也会被释放,线程内核对象的使用计数递减,如果计数为0,则删除该线程内核对象。(可见线程内核对象的生命期可能长于线程本身!)

(4)线程函数必须有一个返回值,它会成为该线程的退出代码。其他线程可以用GetExitCodeThread来检查线程是否己终止运行,并进一步判断其退出代码。

(5)线程函数应尽可能使用函数参数和局部变量。因为静态变量或全局变量,多线程时可能因同时访问这些变量而要进行额外的同步。由函数参数和局部变量是在线程栈上创建的,不会出现多线程同时访问的问题。

6.4 CreateThread函数

参数

描述

psa

指向一个SECURITY_ATTRIBUTES结构体。使用默认安全属性时传入NULL

cbStackSize

①用于指定线程初始时的栈大小,通常传入0即可,此时系统会使用一个合适的大小。默认是1MB(保存在PE文件中!

②线程栈溢出时,产生异常,这可以用来捕获代码中无穷递归bug。若没限制耗尽进程所有的地址空间。

pfnStartAddr

新线程入口函数的地址(注意:新线程和调用CreateThread函数的线程可以同时被执行,这是windows抢占式的特点)

pvParam

传给线程入口函数的参数,可以是一个数值或一个结构体

dwCreateFlags

0——创建后立即执行;CREATE_SUSPENDED——创建后挂起,并不执行

pdwThreadId

得到新线程ID

返回值

成功——线程内核对象的句柄;失败——NULL

6.5 终止运行线程

(1)4种终止线程的方式

终止方式

描述

线程函数返回

强烈推荐 ,这是保证所有资源被正确清理的唯一方式!可以确保以下工作正确执行。

①该函数中的所有C++对象被正确析构。②正确释放线程栈;③把线程退出代码设为函数的返回值;④递减内核对象的计数。

ExitThread

①“杀死主调线程”,操作系统将清理该线程使用的所有操作系统资源(包括线程堆栈

②可以指定dwExitCode为线程的退出代码;③C\C++资源不会被销毁

TerminateThread

杀死任何线程;②线程内核对象减1;③不销毁线程堆栈,微软故意这样做,是为了保证其他线程还可以访问被“杀死”线程栈上的值,该堆栈会等到进程结束时才被释放。③该函数是异步的,函数返回时并不保证另一线程被终止。可用WaitForSingleObject判断线程是否终止。

④将不会通知DLLMain函数某个线程退出,可能导致资源无法释放。

进程终止运行时

①ExitProcess或TerminateProcess会终止进程中所有进程,同时释放资源。

②这两个函数就好象为每个线程调用TerminateThread,所以C++对象的析构不会被调用,数据不会回写磁盘……

(2)线程终止运行时

  ①线程拥有的所有用户对象句柄被释放(如窗口和钩子句柄)

  ②线程退出代码从STILL_ACTIVE变成传给ExitThread或TerminateThread参数的退出代码。

  ③线程内核对象的状态变为触发状态,线程内核对象的使用计数减1

  ④如果线程是进程的最后一个活动线程,则进程也被终止。

 

第6章 线程基础

标签:

原文地址:http://www.cnblogs.com/5iedu/p/4697161.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!