【多线程学习】之一、线程简介
2012-10-01 16:32
218 查看
线程是程序执行的基本原子单位,是进程的一个实体,是CPU调度和分派的基本单位。一个进程可以由多个线程组成。每个线程都有自己的寄存器组,堆栈,输出机制和一个私有消息队列。
多线程可以实现并行的处理,避免了某一项任务长时间的占用CPU的时间,从而导致了其他线程闲置的情况。我们在进行多线程编程的时候要注意,当两个线程优先级非常高的时候,他们抢夺CPU的控制权,在线程切换的时候会消耗很多的CPU资源,会降低系统的性能。
先来看一下创建线程函数:
下面我们来创建一个线程:
当我们使用线程的时候要注意,最好的方式是让线程自然结束。也可以人工的调用TerminateThread函数和ExitThread函数来结束线程,但是当我们用这种方式结束线程的时候,系统不会释放线程使用的堆栈,所以建议大家在编程的时候尽量让线程自己退出。
当我们调用函数退出线程的时候,可能会导致一下几种问题:
1、目标线程拥有临界区,那么windows系统就不会释放临界区。
2、如果线程正在执行某种内核调用,那么该线程的进程内核状态可能不合理。
3、如果目标线程正在操纵共享动态链接库的全局状态,那么windows系统可能破坏动态链接库的状态,从而影响该动态链接库的其他使用者。
操作系统在创建线程的时候有6个步骤,分别是:
1、分配线程内核对象标识和管理新创建的线程,内核对象保存很多系统信息来管理该线程,程内核对象的句柄是CreateThread函数的返回值。
2、把线程的退出代码初始化为STILL_ACTIVE,并把线程的挂起计数设为1.
3、为新线程分配CONTEXT结构。
4、通过保留地址空间区域、为该区域提交两页物理存储器、把提交的存储器的保护标志设为PAGE_READWRITE以及把第二页到顶部的页设为PAGE_GUARD属性来准备线程的堆栈。
5、把LpStartAddr和LopvThread的值放入堆栈的顶部,新线程将其看成传给StartofThread函数的参数。
6、初始化线程的CONTEXT结构中的堆栈指针寄存器,把它指向上步中windows系统放入堆栈的值,然后操作系统初始化执行指针寄存器,使其指向内部的函数,在windows系统执行线程启动函数的第一条执行前执行内部函数。
在上文中,我们一直说线程堆栈,线程堆栈,到底线程堆栈是如何确定其大小的呢?
当我们调用CreateThread函数的时候,在进程的内存地址空间中创建线程的堆栈,在函数中可以指定堆栈的大小,当创建线程以后就不能安全的改变线程的大小了,需要动态的向下增长堆栈。
2012/10/1
jofranks 于南昌
多线程可以实现并行的处理,避免了某一项任务长时间的占用CPU的时间,从而导致了其他线程闲置的情况。我们在进行多线程编程的时候要注意,当两个线程优先级非常高的时候,他们抢夺CPU的控制权,在线程切换的时候会消耗很多的CPU资源,会降低系统的性能。
先来看一下创建线程函数:
HANDLE CreateThread() { LPSECURITY_ATTRIBUTES LPThreadAttributes, //指向SECURITY_ATTRIBUTES的指针 SIZE_T dwStackSize, //表示线程为自己所用堆栈分配的地址空间的大小 系统缺省值为0 LPTHREAD_START-TOUTINE lpStartAddress, //表示新线程开始执行时代码所在函数的地址 即线程函数名 LPVOID lpParameter, //是传入线程函数的参数 DWORD dwCreationFlags, //指定控制线程创建的附加标志 取0线程立即执行 取CREATE_SUSPENDED线程挂起 LPDWORD lpThreadld //是个DWORD类型的地址,返回赋给该新线程的ID }
线程函数lpParameter必须有以下原形:
DWORD WINAPI XXXThreadFun(LPVOID lpParameter) { return(0); }
下面我们来创建一个线程:
#include <windows.h> #include <stdio.h> DWORD WINAPI ThreadFunc( LPVOID lpParam ) //线程函数,跟普通的函数没什么两样 { printf( "Parameter = %d.", *(DWORD*)lpParam ); return 0; } VOID main( VOID ) { DWORD dwThreadId, dwThrdParam = 1; HANDLE hThread; hThread = CreateThread( NULL,0,ThreadFunc,&dwThrdParam, 0,&dwThreadId); if (hThread == NULL) { printf( "CreateThread failed (%d)\n", GetLastError() ); } else { _getch(); CloseHandle( hThread ); } }
当我们使用线程的时候要注意,最好的方式是让线程自然结束。也可以人工的调用TerminateThread函数和ExitThread函数来结束线程,但是当我们用这种方式结束线程的时候,系统不会释放线程使用的堆栈,所以建议大家在编程的时候尽量让线程自己退出。
当我们调用函数退出线程的时候,可能会导致一下几种问题:
1、目标线程拥有临界区,那么windows系统就不会释放临界区。
2、如果线程正在执行某种内核调用,那么该线程的进程内核状态可能不合理。
3、如果目标线程正在操纵共享动态链接库的全局状态,那么windows系统可能破坏动态链接库的状态,从而影响该动态链接库的其他使用者。
操作系统在创建线程的时候有6个步骤,分别是:
1、分配线程内核对象标识和管理新创建的线程,内核对象保存很多系统信息来管理该线程,程内核对象的句柄是CreateThread函数的返回值。
2、把线程的退出代码初始化为STILL_ACTIVE,并把线程的挂起计数设为1.
3、为新线程分配CONTEXT结构。
4、通过保留地址空间区域、为该区域提交两页物理存储器、把提交的存储器的保护标志设为PAGE_READWRITE以及把第二页到顶部的页设为PAGE_GUARD属性来准备线程的堆栈。
5、把LpStartAddr和LopvThread的值放入堆栈的顶部,新线程将其看成传给StartofThread函数的参数。
6、初始化线程的CONTEXT结构中的堆栈指针寄存器,把它指向上步中windows系统放入堆栈的值,然后操作系统初始化执行指针寄存器,使其指向内部的函数,在windows系统执行线程启动函数的第一条执行前执行内部函数。
在上文中,我们一直说线程堆栈,线程堆栈,到底线程堆栈是如何确定其大小的呢?
当我们调用CreateThread函数的时候,在进程的内存地址空间中创建线程的堆栈,在函数中可以指定堆栈的大小,当创建线程以后就不能安全的改变线程的大小了,需要动态的向下增长堆栈。
2012/10/1
jofranks 于南昌
相关文章推荐
- Java学习笔记—多线程(简介、线程创建)
- 我的安卓学习之路--Java多线程--线程简介
- 【多线程学习】之一、线程简介
- 多线程编程之进程、线程、进程间通信、线程间通信简介
- 多线程学习-停止线程
- linux多线程学习设置线程调度权限
- JAVA多线程学习3--线程一些方法
- java多线程与并发之java线程简介(五)
- 马士兵-多线程学习第01课 线程的创建和启动
- Java6学习笔记56——多线程编程——线程的创建方法2
- 关于多线程学习总结(二) 了解线程的属性及方法
- Java多线程学习1,使用线程的三种方式
- Java多线程学习(单一线程)
- 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题
- 多线程学习--案例-子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次
- [原]Java多线程编程学习笔记之一:线程中断(含代码)
- java 多线程学习笔记之进程和线程
- java多线程学习之创建线程与线程间通信
- java学习之浅谈多线程3--线程间协作
- 4.多线程学习--操作线程的中断机制