信号,互斥量,事件,可等待计时器
1. 关键段只能对同一进程的线程进行同步,且无法设置最长等待时间,所以容易死锁。
使用内核对象的唯一缺点是它们的性能。调用本章的函数,线程都需要从用户模式切换到内核模式。
内核对象状态:触发signaled,未触发 nosignaled
为了理解,可以把内核对象当作旗帜,触发,旗帜升起,未触发,旗帜降下。当线程等待的对象处于未触发状态(旗帜落下)的时候,它们是不可调度的。但是一旦对象被触发(旗帜升起),那么线程就会看到这面旗帜。从而变为可调度状态,然后很快就会继续执行。(线程,进程变为触发后无法改回未触发)
2. 等待函数 waitforsingleobject
等待函数使一个线程资源进入等待状态,直到指定的内核对象被触发或者达到等待时间为止。对方事前已触发,则线程无法进入等待状态。
waitformuiltipleobjects 可指定多个触发或单个触发(原子操作)。 副作用。
3. 事件内核对象
用途: 一个线程执行初始化操作(创建之后的线程等待,创建事件),然后在初始化后触发时间,则等待该时间的线程进入可调度状态 p238 例子
在创建事件时指定手动重置或自动重置,手动重置使全部等待线程可调度,自动重置使一个可调度(setEvent)
4. 可等待的计时器内核对象
可设置定时器,如2008年1月1日下午1;00触发,以后每6小时触发一次
用户计时器 settimer vs 可等待计时器
用户计时器需要在应用程序中使用大量的用户界面基础设施,从而消耗更多资源。此外,可等待计时器是内核对象,这意味着它们不仅可以在多线程间共享,而且更具安全性。
当一个用户计时器触发时,只有一个线程会得到通知。
setTimer 函数原型 setTimer(窗口句柄,定时器id,时间,回调函数)
mfc中setTimer被封装,在cwnd类中,调用不需要指定窗口句柄。原型变为:
setTimer(定时器id, 时间,回调函数)
回调函数默认为onTimer,也可以自己进行指定。
5. 信号量内核对象
信号量内核对象用来对资源计数,最大资源计数和当前资源计数
当前资源计数大于0 触发状态
当前资源计数等于0 信号量处于触发状态
releaseSemaphore 使当前资源计数加1
课本翻译有点问题,自己整理后,大意应为:
当前资源计数表示信号量当前可用资源数量cnt
cnt刚开始被初始化为0,表示未触发
一旦被触发,cnt被初始化为最大资源计数,先检查cnt是否大于0,若大于0,则每次请求信号量使得cnt减1。释放则使cnt加1
6. 互斥内核对象
互斥量(mutex)内核对象用来确保一个线程独占对一个资源的访问,互斥量对象包含一个使用计数,线程id 以及一个递归计数。互斥量与关键段的行为完全相同,但是,互斥量是内核对象,而关键段是用户模式下的同步对象,这意味着互斥量比关键段慢,但这同时意味着不同进程中的线程可以反问同一个互斥量。这还意味着线程可以在等待对资源的访问权时指定一个最长等待时间。(waitforsingleobject)
可能多次等待一个互斥量,使得递归计数大于1,要多次releasemutex才可以释放互斥量。互斥量具有线程所有权。
7. 线程同步速查表
8. 其他线程同步函数
异步I/O: 允许线程开始读取操作或写入操作,但线程不必等待操作完成。例如,如果线程需要把一个大文件载入内存中,那么线程可以告诉系统把文件载入内存中,而自己忙别的任务。设备对象是可同步内核对象,这意味着我们可以调用waitforsingleobject,并传入文件句柄或套接字,通信端口等。当系统执行异步io时,设备对象处于未触发状态,一旦操作完成,系统会将对象变为触发状态,这样线程就知道操作已经完成了。
(but)线程仍会被临时挂起,损害性能。---->继续改进,io完成端口。下章介绍。
各种wait函数
使用等待遍历api来检测死锁