第一章
这一章主要介绍了为什么要引入多线程,以及多线程技术在windows系统中的发展历史。
内存大致可以分为3中类型,分别是code,data和stack。code是程序的可执行部分,一定是只读性质。只是cpu唯一允许执行的内存 。data是程序中的所有变量(不包括函数中的局部变量),可分为全局和静态变量两种。stack是你调用函数时所用的堆栈空间,其中有局部变量。每个线程产生时配有一个堆栈。
第二章 线程的第一次接触
(1) 产生一个线程
LPSECURITY_ATTRIBUTES lpThreadAttributes, //施行于这一线程的security属性
DWORD dwStackSize, //新线程有自己的堆栈,0表示缺省大小1MB
LPTHREAD_START_ROUTINE lpStartAddress, //新线程运行的函数指针
LPVOID lpParameter, //上一个函数的参数
DWORD dwCreationFlags, //允许产生那个一个暂时挂起的线程,默认立即运行
LPDWORD lpThreadID //新线程的ID会被回传到这里
HANDLE hObject //代表一个已打开对象之handle
);
返回值:如果CreateThread()成功,传回一个handle,代表新线程。否则传回一个FALSE。如果失败,可以调用GetLastError()获知原因。
其中,新线程的运行函数的原型是:
[in] LPVOID lpParameter
);
(2)核心对象
CreateThread传回2个值,用以识别一个新的线程。第一个是HANDLE,就是他的返回值。大部分与线程有关的API函数都需要它。第二个是有lpThreadID带回来的线程ID,线程ID是一个全局变量,可以唯一地表示系统中任一进程的某个线程。
wind32核心对象有进程(processes),线程(threads),文件(files),事件(events),信号量(semaphores),互斥器(mutexes)和管道(pipes).
GDI对象和核心对象的不同。GDI对象有单一的拥有者,不是进程就是线程;核心对象 可以有一个以上的拥有者,甚至可以跨进程。
(3)CloseHandle的重要性
HANDLE hObject //代表一个已打开对象的handle
);
返回值:如果成功返回TRUE。失败返回FALSE。
如果一个进程没有在结束之前针对它所打开的核心对象调用CloseHandle,操作系统会自动把那些对象的引用计数下降一。如果一个进程常常产生“worker”线程二不管他,那么这个进程可能最终有数百个开启的“线程核心对象”留给系统区清理。这样的资源泄漏会对效率产生负面影响。
不可以依赖“因线程的结束而清理所有被这一线程产生的核心对象”。许多对象,是被进程拥有,而非被线程拥有。在进程结束之前不能够清理他们。
当你调用CloseHandle应给予它一个线程 handle时,只不过是表示,你希望自己和次核心对象不再有任何瓜葛。CloseHandle唯一做的事情就是把引用计数减一。如果该值编程0,对象会自动被操作系统摧毁。
”线程核心对象“ 引用到的那个线程也会令核心对象开启。因此,线程对象的默认引用计数是2.
(4)线程结束代吗
线程的结束代码表示了线程的状态,可以调用GetExitCodeThread。
HANDLE hThread, //由CreateThread传回的线程handle
LPDWORD lpExitCode //指向一个DWORD,用以接受结束代码(exit code)
);
返回值:如果成功,GetExitCodeThread传回TRUE,否则传回FALSE。如果线程已结束,那么线程的结束代码会被放在lpExitCode参数中带回来。如果未结束,lpExitCode带回来的是STILL_ACTIVE.
(5)强制结束一个线程
ExitThread可以强制结束一个线程
DWORD dwExitCode //指定此线程之结束代码
);
程序启动后就执行的那个线程称为主线程(primary thread)。主线程有2个特点。第一,他必须负责GUI程序中的主消息循环。第二,这一线程的结束会使得程序中的所有线程都被强迫结束,程序也因此结束。其他线程没有机会做清理工作
(6)微软多线程模型
win32说明文件强调线程分为GUI线程和worker线程。GUI线程负责建造 窗口以及处理主消息循环。worker负责执行纯粹运算工作,如重新计算等,他们会导致主线程的消息队列失去反映。一般而言,GDI线程绝不会去做那些不能够马上完成的工作。
GUI线程的定义是:拥有消息队列的线程。任何一个特定窗口的消息总是被产生这一窗口的线程抓到并处理。所有对此窗口的改变也都应该由该线程完成。
如果worker线程也产生了一个窗口,那么就会有一个消息队列也随之产生并且附加到此线程上。于是worker线程就变为一个GUI线程 。不过,worker线程不能产生窗口,对话框,消息框会其他与UI有关的东西。
如果一个worker线程需要输入或输出错误消息,应该授权给UI线程来做,并将结果通知给worker线程。
唯一能把数据安全交给线程的地方,就是heap
(7)总结
设计多线程程序的关键:
- 各线程的数据要分离开来,避免使用全局变量。
- 不要再线程之间共享GDI对象。
- 确定你知道你线程的状态。不要径自结束程序而不等待他们的结束。
- 让主线程处理用户界面(UI)