线程简介

线程是程序执行的基本原子单位,是进程的一个实体,是CPU调度和分派的基本单位。一个进程可以由多个线程组成。每个线程都有自己的寄存器组,堆栈,输出机制和一个私有消息队列。

多线程可以实现并行的处理,避免了某一项任务长时间的占用CPU的时间,从而导致了其他线程闲置的情况。我们在进行多线程编程的时候要注意,当两个线程优先级非常高的时候,他们抢夺CPU的控制权,在线程切换的时候会消耗很多的CPU资源,会降低系统的性能。

先来看一下创建线程函数:

  1. <span style="font-size: 18px; ">HANDLE CreateThread()  
  2. {  
  3.     LPSECURITY_ATTRIBUTES LPThreadAttributes,  //指向SECURITY_ATTRIBUTES的指针  
  4.     SIZE_T dwStackSize,                        //表示线程为自己所用堆栈分配的地址空间的大小 系统缺省值为0  
  5.     LPTHREAD_START-TOUTINE lpStartAddress,     //表示新线程开始执行时代码所在函数的地址 即线程函数名  
  6.     LPVOID lpParameter,                        //是传入线程函数的参数  
  7.     DWORD dwCreationFlags,                     //指定控制线程创建的附加标志 取0线程立即执行 取CREATE_SUSPENDED线程挂起  
  8.     LPDWORD lpThreadld                         //是个DWORD类型的地址,返回赋给该新线程的ID  
  9. }  
  10. </span> 
线程函数lpParameter必须有以下原形:

 
 
  1. DWORD WINAPI XXXThreadFun(LPVOID lpParameter)  
  2. {  
  3.     return(0);  
  4. }  


下面我们来创建一个线程:

  1. #include <windows.h>  
  2. #include <stdio.h>  
  3. DWORD WINAPI ThreadFunc( LPVOID lpParam )                         //线程函数,跟普通的函数没什么两样  
  4. {   
  5.     printf( "Parameter = %d.", *(DWORD*)lpParam );   
  6.     return 0;   
  7. }   
  8.    
  9. VOID main( VOID )   
  10. {   
  11.     DWORD dwThreadId, dwThrdParam = 1;   
  12.     HANDLE hThread;   
  13.     hThread = CreateThread( NULL,0,ThreadFunc,&dwThrdParam, 0,&dwThreadId);   
  14.    if (hThread == NULL)   
  15.    {  
  16.       printf( "CreateThread failed (%d)\n", GetLastError() );   
  17.    }  
  18.    else   
  19.    {  
  20.       _getch();  
  21.       CloseHandle( hThread );  
  22.    }  
  23. }  


当我们使用线程的时候要注意,最好的方式是让线程自然结束。也可以人工的调用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函数的时候,在进程的内存地址空间中创建线程的堆栈,在函数中可以指定堆栈的大小,当创建线程以后就不能安全的改变线程的大小了,需要动态的向下增长堆栈。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值