作为一个C++程序员,相信大家对多线程都不陌生。最近自己在系统的学习多线程编程,发现了很多曾经没有注意到的东西,系统的整理了一下这些知识。方便自己以后查阅,也希望能够能够方便他人。
一、线程基础
1. 作业—> 进程—> 线程
作业:进程组的概念,将进程添加到一个作业中,能够通过作业内核对象来集中控制,设置一些额外的属性。
进程:一个正在运行的程序实例,由系统用来管理进程的内核对象和地址空间组成。进程时不活泼的,它只是线程的容器,每个进程必须有一个线程。
线程:程序执行流的最小单元,必须在某个进程环境中创建,由线程内核对象和线程堆栈组成。
2. 进程被初始化时,系统就会创建一个主线程,主线程的进入点函数必须为:main、wmain、WinMain、wWinMain。
3. 线程创建函数:CreateThread()、_beginthreadex();(建议后者,前者有可能造成内存泄露)
CreateThread(): 系统API
_beginthreadex(): CRT(c运行期可函数)(参数与上面一样)
HANDLE CreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes,//安全属性 NULL默认
SIZE_T dwStackSize,//initialstacksize 出事栈大小,0默认
LPTHREAD_START_ROUTINE lpStartAddress,//threadfunction线程函数地址
LPVOID lpParameter,//threadargument 传递给线程函数的参数
DWORDdwCreationFlags,//creationoption 线程标志,挂起或者激活(0)
LPDWORDlpThreadId//threadidentifier 返回线程ID
)
_beginthreadex()内部会调用CreateThread()函数,但是在调用CreateThread函数之前,它会为线程申请一个_tiddata结构,用于存储线程相关数据;如线程ID,线程handle,errno值等等。线程结束_beginthreadex()内部会自动调用_endthreadex(), _endthread()会释放掉_tiddata结构分配的内存,并且会调用CloseHandle()来关闭线程句柄。
调用CreateThread()函数来创建的线程,不会为线程分配_tiddata结构。但是当我们调用某些C运行期库函数时,如:strtok(),就会需要_tiddata这个结构,就会发现线程没有申请_tiddata结构,这时它会申请这个结构并且初始化。可是这个自动申请的结构谁来释放呢?
当一个进程/线程开始或者退出时,每个DLL的DllMain都会被调用,在DllMain中会释放掉线程的_tiddata。可是静态链接库没有DllMain,这样就没办法释放掉_tiddata,这是可能造成内存泄露的一种情况。
4. 线程终止:
线程函数返回 (最好使用此方式)
ExitThread() (某些资源不能撤销,如:C++类对象)
TerminateThread() (异步运行函数,不能保证线程被撤销)
进程终止
二、线程间通信
1. 全局数据结构。与同属一个进程的其它线程共享进程所拥有的全部资源。
2. 参数
3.PostThreadMessage(),线程之间异步通讯,将消息放入指定线程的消息队列里,不等待线程处理消息就返回。
PostThreadMessage()有时会失败,报1444错误。可能是线程不存在,也有可能是线程不存在消息队列。调用PeekMessage或GetMessage会强制系统为该线程创建消息队列。