Windows Store 没有 Win32 线程 的 API,没有线程局部存储(TLS)API,一些线程同步内核对象相关 API 也不全。
Windows Store 缺失的 线程相关 API 有:
缺失API | 实现方法 | 说明 |
CreateThread | ThreadPool | 返回的 pdwThreadId 无效 |
ResumeThread | 没有 SuspendThread 对应 | |
SetThreadPriority | 只能在暂停状态调用 | |
Sleep | WaitForSingleObjectEx | |
TlsAlloc | __declspec(thread) | 自己管理分配 |
TlsFree | 自己管理分配 | |
TlsGetValue | 自行实现 | |
TlsSetValue | 自行实现 | |
InitializeCriticalSection | InitializeCriticalSectionEx | |
CreateEventW | CreateEventExW | |
CreateEventA | CreateEventW | |
CreateMutexW | CreateMutexExW | |
CreateMutexA | CreateMutexW | |
OpenMutexA | OpenMutexW | |
CreateSemaphoreW | CreateSemaphoreExW | |
CreateSemaphoreA | CreateSemaphoreW | |
OpenSemaphoreA | OpenSemaphoreW | |
WaitForSingleObject | WaitForSingleObjectEx | |
WaitForMultipleObjects | WaitForMultipleObjectsEx | |
_beginthreadex | CreateThread |
线程的实现要点:
- 实现基础
Windows Store 提供了 Windows::System::Threading::ThreadPool 线程池对象。通过向 ThreadPool 添加工作对象 WorkItemHandler 可以达到多线程运行的目的。
- 线程实例管理
管理一个全局线程信息集合,需要加锁保护,可以使用 std::mutex
- 线程的句柄
线程句柄应该是一个内核对象,可以创建一个 Event 对象代替
- 线程的ID
Windows Store 保留了获取当前线程ID的API GetCurrentThreadID,但是需要被创建的线程运行起来才能获取,还需要通过某种方式返回给线程创建者,比较麻烦。基于线程ID不常使用的现实,CreateThread 返回的线程ID无效。
- 等待线程结束
之前返回的线程句柄是一个Event 对象,可以直接 Wait 这个对象,另外线程执行快结束时,设置这个 Event
- 以暂停状态创建
只创建线程相关信息,并加入集合,不加入 ThreadPool 执行,就处于暂停状态
- 恢复线程执行
将线程相关的 WorkItemHandler 加入 ThreadPool 执行
- 设置运行优先级
设置 WorkItemHandler 的优先级 nPriority
- 终止线程
无法强行终止线程,只能等待线程正常结束
线程局部存储的实现:
- 实现基础
利用 __declspec(thread) 数据属性定义变量,该变量每个线程有自己的一份。将该变量定义为指针数组指针 std::vector<void *> *,初始值为 NULL。某个线程访问局部存储时,如果对应的指针为空,则创建一个数组。这里不需要加锁保护。
- 实例管理
需要管理数组索引分配和回收,需要加锁保护。
Sleep的实现
创建一个全局 Event 对象,永远不会设置信号。Wait 这个 Event,带上相应的超时时间,多个线程同时调用 Sleep,可以同时 Wait 这个 Event。