本文基于本校计算机学院的教程和自己的体会改编,并不是特别的干货,不过适合新人入门看看:
首先得知道什么是进程什么是线程?(水,非干货)
一个通俗的解释是,进程是指在系统中正在运行的一个应用程序;程序一旦运行就是进程,或者更专业化来说:进程是指程序执行时的一个实例。线程是进程的一个实体。进程——资源分配的最小单位,线程——程序执行的最小单位。
在我们学校的教材中,进程通常被定义为一个正在运行的程序的实例,是动态的。如果把程序比作菜谱,那么进程就是按照菜谱做菜的过程,当运行一个可执行程序就启动了该程序的一个实例,即创建了一个进程。当我此时正在补这一篇csdn的时候,电脑放着歌,TIM也在闪动,我也在向这个网站上输入文字,一台机器可以同时进行着多个进程,这就是进程的并发特征。他们其实看起来是在同时进行,实则是轮流使用着CPU的时间片的,只是因为时间片很短,所以用户感受不到这种变换。
进程具有并发性,那么有没有可能在一个程序内部,也可以有多个任务并发独立执行呢?
那系当然的啦~使用线程可以达到目的。线程是进程内部的一个执行单元。每一个进程至少有一个这样的执行单元,称之为主线程,它无需由用户去主动创建而是系统主动创建的。主线程终止,则该进程也随之终止。在C语言中,主线程的执行代码入口就是main函数。当然用户可以根据需要在主线程执行过程中创建其他线程,多个线程并发的存在于一个进程中。比如在bupt的电梯一楼,你可以按下“上”的同时,看到显示屏上实时输出电梯的运行状态的变化。
多线程可以并发的运行在同一个进程之中,实现并行处理,避免某项任务长时间占用CPU时间,因此多线程技术的应用也非常广泛。
如果需要多个任务并发执行,因此肯定需要用到线程,那么如何在我们的程序中创建线程呢?(水,非干货)
创建线程可以使用Windows操作系统提供的API函数CreateThread来完成,该函数将会创建一个线程并且返回已建线程的句柄(英文叫做handle)。
该函数的原型声明如下描述:
HANDLE CreateThread(LPSECURRY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadid)
其中,lpThreadAttributes指向一个SECURITY_ATTRIBUTES结构的指针,该结构决定了线程的安全属性,一般置为NULL;
dwStackSize:设置线程初始栈的大小,即线程可以将多少地址空间用于自身的栈区,一般都默认为0,表示用多少要多少。
lpStartAddress:新线程开始执行时代码所在函数的地址,即线程的起始地址
lpParameter:制定了线程执行时传给线程的参数
dwCreationFlags:控制线程创建的附加标志,有两种取值。0:创建后提及执行;CREATE_SUSPENDED,则线程创建后处于挂起状态并不马上执行,直至函数ResumeThread被调用。
lpThreadId:接受线程ID,不感兴趣弄成NULL就是了。
比如下面:
#include <stdio.h>
#include<windows.h>
DWORD WINAPI Fun(LPVOID lpParameter);
int main()
{
HANDLE hThread1;//<1>
hThread1=CreateThread(NULL,0,Fun,NULL,0,NULL); //<2>
CloseHandle(hThread1);//<3>
printf("Damn,main thread is running\n"); //<4>
return 0;
}
DWORD WINAPI Fun(LPVOID lpParameter)
{
printf("yes,sir,Fun thread is running\n");
return 0;
}
运行出来就是damn,main thread is running
解释一下:
1.包含windows.h(要用到win的api)
2.线程函数就意思意思一下
3.main作为主线程,可以在其中创建新的线程,首先调用CreateThread创建一个新的线程,第一个参数设成NULL表示默认安全性,第二个参数为0表示调用默认的栈区空间(需要多少拿多少,和下载游戏时候的设置一样的),第三个参数是指定线程的入口函数的接口;第四个参数是传递给线程1的参数,这里不需要,所以写成NULL,第五个是希望线程一旦创建就开始执行而不是suspended;最后一个参数是用于指向线程id的变量,因为这里不需要id信息,也设置成NULL。
4.创建线程完毕之后,调用Close Handle函数关闭新线程的句柄。刚刚创建了线程,为啥又把他关闭呢?实际上,Close Handle函数并没有终止新创建的线程,只是表示在主线程中对新建的线程句柄不是很感兴趣而已,因此把他关了。
5.那么为什么要关闭线程的句柄呢?线程的内核对象有一个引用计数器,该计数器初始值是一,当创建线程计数器+1,当关闭线程句柄或者线程执行完毕之后,计数器-1.当线程引用计数器为0时候,系统就会释放线程内核对象。记住当如果不再需要线程句柄的时候应该把他关了就行。
6.为什么最后只有主线程那句话运行了呢?这个问题请见我下一篇线程水文。