线程内核对象
线程的终止
线程的优先级
多线程
进程---主线程---辅助线程
主线程在运行过程中还可以创建新的线程,即多线程。在同一进程中运行不同的线程的好处是这些线程可以共享进程的资源,如全局变量,句柄等。各个线程也可以用自己私有的堆栈用于保存私有数据。
线程描述了进程内代码的执行路径。进程内可以有多个线程来执行,为了使他们‘同时’运行,操作系统为每个线程轮流分配CPU的时间片。
一般情况下,应用程序使用主线程接收用户的输入、显示运行的结果,而创建新的线程来处理长时间的操作。
每个线程必须有一个进入点函数,线程从这个进入点开始运行。
1、线程函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
WINAPI是一个宏名,在windef.h文件中声明
#define WINAPI _stdcall
_stdcall是新标准C/C++函数的调用方法。调用方法参数的进栈顺序和_cdecl一样,都是从右到左,区别:
_stdcall:自动清栈
cdecl:手动清栈
Windows规定,凡是由它调用的函数都必须定义为_stdcall类型
ThreadProc是一个回调函数,即由Windows负责调用的函数。
2、创建新线程函数
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttribute, // 线程安全性
DWORD dwStackSize m, //指定线程堆栈大小
LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数起始地址
LPVOID lpParameter, // 传递给线程函数的参数
DWORD dwCreationFlags, // 指定线程创建后是否立即启动
DWORD* lpThreadId // 用于取得内核给新线程分配的ID号
)
函数执行成功,返回新建线程的线程句柄,lpStartAddress参数指定线程函数的地址,新建线程将从此地址开始执行,直到return语句返回,线程结束,把控制权交给操作系统。
2.1 需要注意的两个参数
lpThreadAttribute:一个指向LPSECURITY_ATTRIBUTES结构的指针,如果需要默认安全属性,传递NULL,如果希望此线程对象句柄可以被子进程继承的话,必须设定一个LPSECURITY_ATTRIBUTES结构。将它的bInheritHandle成员初始化为TRUE。
LPSECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; // 使CreateThread返回的句柄可以被继承
HANDLE h = ::CreateThread(&sa,...); // 句柄h可以被子进程继承
dwCreateFlags:创建标志,如果是0,表示线程被创建后立即开始执行,如果指定为Create_SUSPENDED标志,表示线程被创建以后处于挂起状态,直到使用ResumeThread函数显式启动线程为止。
3、WaitForSingleObject(hHandle , dwMilliseconds)函数
hHandle:要等待对象的句柄
dwMilliseconds:要等待的时间
该函数用于等待指定的对象变成受信状态
函数返回条件
1)等待的对象变为受信状态
2)参数dwMilliseconds指定的时间已经过去
4、实例
#include
#include
using namespace std;
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
int i = 0;
while (i < 10)
{
printf("我是一个来自线程的输出%d\n", i++);
}
return 0;
}
int main()
{
HANDLE hThread;
DWORD dwThreadId;
// 创建线程
hThread = ::CreateThread(NULL,// 默认安全属性
NULL, // 默认堆栈
ThreadProc,// 线程的入口函数
NULL, // 默认的线程参数
0, // 线程立即执行
&dwThreadId); // 线程ID
printf("现在一个新线程即将启动,新线程的Id是%d\n",dwThreadId);
system("pause");
return 0;
}
4.1 运行结果
为什么启动线程之后,不是立即执行线程代码里面的内容,而是执行“现在一个新线程即将启动,新线程的Id是10776”?
因为线程启动之后,并不是立即获得CPU时间片的,而是处于就绪队列,等待系统将当前的时间片运行完毕,才将线程从就绪队列拉进运行状态的。因此造成了先执行主函数中的printf函数,再执行线程函数里面的内容。