多线程的同步执行、多线程和GDI 对象、线程局部存储、在线程中创建窗口、terminiate 线程、线程安全和访问权限

多线程的同步执行

为了避免冲突和思索,有必要同步多线程对共享资源的访问。当需要确保以适当的顺序执行相互依赖的代码,同步也是必要的。有一些对象的句柄可以被用来进行同步,这包括:

1. 控制台输入缓存

2. 事件

3. 互斥体

4. 进程

5. 信号量

6. 线程

7. 定时器

这些对象的状态,或者是有信号,或者没信号。当调用等待函数wait functions,并传入了这些对象中的一个的句柄,调用线程将被阻塞,直到指定的对象成为有信号的状态。

对于单进程的线程的来说,关键区对象比互斥体的效率更高。临界区类似互斥锁,一次启用一个线程来使用受保护资源。线程可以调用EnterCriticalSection 函数请求一个关键区的拥有权,如果它已经被另外的线程拥有了,调用线程将被阻塞。线程可以调用TryEnterCriticalSection 请求对一个关键区的拥有权,不会阻塞调用,而会返回False。它拥有了拥有权后,可以自由的访问共享资源。其他线程的执行不受影响,除非它们尝试进入到关键区。

WaitForInputIdle 函数将使调用线程等待,直到一个特定的线程被初始化,并等待没有输入挂起的用户输入。调用WaitForInputIdle 可以用来同步父进程和子进程,因为CreateProcess 在创建子进程后,不会等待其完成初始化。

更多信息请参见:Synchronization.

多线程和GDI 对象

为了增强性能,对图形设备接口(GDI)对象(例如调色板、设备上下文、区域等)的访问is not serialized?这位具有共享这些对象的多个线程的进程创建了潜在的危险。例如,一个线程删除GDI 对象而另一个线程正在使用它,结果不可预测。仅通过不共享GDI 对象就可以避免这种危险,如果共享是不可避免的,应该使用同步操作。

线程局部存储

https://blog.csdn.net/qq_18218335/article/details/69357016

进程中所有的线程共享它的虚拟地址空间。执行函数的每个线程的函数内的局部变量是属于自己的。但,静态变量和全局变量是在进程内的所有线程内共享的。通过TLS,可以给线程提供一个唯一的值,进程这时候使用了一个全局索引。一个线程申请索引,其他线程可以使用这个索引,得到绑定的唯一的值。

TLS_MINIMUM_AVAILABLE 定义了在一个进程中能够使用的最大的TLS 的索引。所有的系统中,这个值最少为64.最大1088.具体详情,参考上面的文章。

在线程中创建窗口

任何线程都可以创建窗口。创建窗口的线程拥有该线程以及绑定的消息队列。因此,线程必须提供一个消息循环,以处理它的消息队列中的消息。另外,必须调用MsgWaitForMultipleObjects 或 MsgWaitForMultipleObjectsEx 在该线程中,而不是其他的等待函数,由此它可以处理消息。否则,当线程等待的时候发送一个消息,他可能死锁。

AttachThreadInput,可以让一些线程共享同一个输入状态。通过共享输入状态,这些线程共享它们的活动窗口的内容。通过这样做,一个线程总是可以激活另一个线程的窗口。此功能对于在共享输入状态的不同线程创建的窗口之间共享焦点状态,鼠标捕获状态,键盘状态和窗口Z 顺序状态也很有用。有关创建窗口的信息,参见:Windows Classes.

停止一个线程的执行

停止一个线程有如下的结果:

1. 线程拥有的资源,比如windows 和 hooks 被释放

2. 设置线程exit code

3. 线程对象为有信号

4. 如果线程是进程中唯一的活跃的活动的线程,该进程被terminated。

GetExitCodeThread 函数,返回线程的exit code。当一个线程在执行,它的exit code 是STILL_ACTIVE。当一个线程被终止,它的终止状态修改为线程的exit code。

当一个线程结束,线程对象的状态改为有信号,释放所有的正在等待该线程被终止的线程。

当一个线程终止,直到所有的指向它的线程对象的句柄被关闭后,线程对象才被释放。

线程如何终止

线程执行,直到下面的某个事件发生:

1. 线程调用ExitThread

2. 线程所属于的进程调用ExitProcess

3. 线程函数返回

4. 任何的线程,调用TerminateThread(本线程句柄)

5. 任何的线程,调用TerminateProcess(本进程句柄)

exit code = ExitThread、ExitProcess、TerminateThread、TerminateProcess 或线程函数的返回值

如果一个线程被ExitThread 退出,系统调用所有的附着的DLL 的入口点,并传入,知识线程detach 的值(除非DLL 调用了DisableThreadLibraryCalls)。如果一个线程被Exitprocess 终止,DLL 入口点,仅被调用一次,指示DLL Detach。当线程被TerminateThread 或 TerminateProcess 终止,DLL 不被通知。更多信息参见:Dynamic-Link Libraries.

TerminateThread和TerminateProcess函数只应在极端情况下使用,因为它们不允许线程清理,不通知附加的DLL,也不释放初始堆栈.此外,在进程终止之前,不会关闭对线程拥有的对象的句柄。以下步骤提供了更好的解决方案:

1. 使用CreateEvent 创建一个事件对象

2. 创建线程

3. 每个线程通过WaitForSingleObject 监控事件的状态。使用的wait time-out 间隔为0

4. 当事件为有信号状态,每个线程终止自己的执行(WaitForSingleObject 返回WAIT_OBJECT_0)

线程安全和访问权限

这个内容太多了,足够开另一个专题,这些文章的主题是多线程,暂时跳过安全话题。

发布了93 篇原创文章 · 获赞 13 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_18218335/article/details/84261764