00001 00002 // 00003 // Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved 00004 // 00006 00007 /* 00008 * Emulates a subset of the Win32 threading API as a layer on top of WinRT threadpools. 00009 * 00010 * Supported features: 00011 * 00012 * - CreateThread (returns a standard Win32 handle which can be waited on, then closed) 00013 * - CREATE_SUSPENDED and ResumeThread 00014 * - Partial support for SetThreadPriority (see below) 00015 * - Sleep 00016 * - Thread local storage (TlsAlloc, TlsFree, TlsGetValue, TlsSetValue) 00017 * 00018 * Differences from Win32: 00019 * 00020 * - No ExitThread or TerminateThread (just return from the thread function to exit) 00021 * - No SuspendThread, so ResumeThread is only useful in combination with CREATE_SUSPENDED 00022 * - SetThreadPriority is only available while a thread is in CREATE_SUSPENDED state 00023 * - SetThreadPriority only supports three priority levels (negative, zero, or positive) 00024 * - TLS requires use of this CreateThread (leaks memory if called from other threadpool tasks) 00025 * - No thread identifier APIs (GetThreadId, GetCurrentThreadId, OpenThread) 00026 * - No affinity APIs 00027 * - No GetExitCodeThread 00028 * - Failure cases return error codes but do not always call SetLastError 00029 */ 00030 00031 #pragma once 00032 00033 namespace AK 00034 { 00035 namespace ThreadEmulation 00036 { 00037 HANDLE WINAPI CreateThread(__in LPTHREAD_START_ROUTINE lpStartAddress, __in_opt LPVOID lpParameter, __in DWORD dwCreationFlags); 00038 DWORD WINAPI ResumeThread(__in HANDLE hThread); 00039 BOOL WINAPI SetThreadPriority(__in HANDLE hThread, __in int nPriority); 00040 00041 VOID WINAPI Sleep(__in DWORD dwMilliseconds); 00042 VOID WINAPI SleepEx(__in DWORD dwMilliseconds, BOOL in_bAlertable ); 00043 } 00044 } 00045 00046 #ifdef AK_IMPLEMENT_THREAD_EMULATION 00047 00048 #include <assert.h> 00049 #include <vector> 00050 #include <set> 00051 #include <map> 00052 #include <mutex> 00053 00054 namespace AK 00055 { 00056 namespace ThreadEmulation 00057 { 00058 // Stored data for CREATE_SUSPENDED and ResumeThread. 00059 struct PendingThreadInfo 00060 { 00061 LPTHREAD_START_ROUTINE lpStartAddress; 00062 LPVOID lpParameter; 00063 HANDLE completionEvent; 00064 int nPriority; 00065 }; 00066 00067 static std::map<HANDLE, PendingThreadInfo> pendingThreads; 00068 static std::mutex pendingThreadsLock; 00069 00070 00071 // Converts a Win32 thread priority to WinRT format. 00072 static Windows::System::Threading::WorkItemPriority GetWorkItemPriority(int nPriority) 00073 { 00074 if (nPriority < 0) 00075 return Windows::System::Threading::WorkItemPriority::Low; 00076 else if (nPriority > 0) 00077 return Windows::System::Threading::WorkItemPriority::High; 00078 else 00079 return Windows::System::Threading::WorkItemPriority::Normal; 00080 } 00081 00082 00083 // Helper shared between CreateThread and ResumeThread. 00084 static void StartThread(LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, HANDLE completionEvent, int nPriority) 00085 { 00086 auto workItemHandler = ref new Windows::System::Threading::WorkItemHandler([=](Windows::Foundation::IAsyncAction^) 00087 { 00088 // Run the user callback. 00089 lpStartAddress(lpParameter); 00090 00091 // Signal that the thread has completed. 00092 SetEvent(completionEvent); 00093 CloseHandle(completionEvent); 00094 00095 }, Platform::CallbackContext::Any); 00096 00097 // Start the threadpool task. 00098 auto workItem = Windows::System::Threading::ThreadPool::RunAsync(workItemHandler, GetWorkItemPriority(nPriority), Windows::System::Threading::WorkItemOptions::TimeSliced ); 00099 00100 // workItem->Start(); 00101 } 00102 00103 00104 HANDLE WINAPI CreateThread(__in LPTHREAD_START_ROUTINE lpStartAddress, __in_opt LPVOID lpParameter, __in DWORD dwCreationFlags) 00105 { 00106 // Validate parameters. 00107 assert((dwCreationFlags & ~CREATE_SUSPENDED) == 0); 00108 00109 // Create a handle that will be signalled when the thread has completed. 00110 HANDLE threadHandle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, STANDARD_RIGHTS_ALL|EVENT_MODIFY_STATE); 00111 00112 if (!threadHandle) 00113 return nullptr; 00114 00115 // Make a copy of the handle for internal use. This is necessary because 00116 // the caller is responsible for closing the handle returned by CreateThread, 00117 // and they may do that before or after the thread has finished running. 00118 HANDLE completionEvent; 00119 00120 if (!DuplicateHandle(GetCurrentProcess(), threadHandle, GetCurrentProcess(), &completionEvent, 0, false, DUPLICATE_SAME_ACCESS)) 00121 { 00122 CloseHandle(threadHandle); 00123 return nullptr; 00124 } 00125 00126 try 00127 { 00128 if (dwCreationFlags & CREATE_SUSPENDED) 00129 { 00130 // Store info about a suspended thread. 00131 PendingThreadInfo info; 00132 00133 info.lpStartAddress = lpStartAddress; 00134 info.lpParameter = lpParameter; 00135 info.completionEvent = completionEvent; 00136 info.nPriority = 0; 00137 00138 std::lock_guard<std::mutex> lock(pendingThreadsLock); 00139 00140 pendingThreads[threadHandle] = info; 00141 } 00142 else 00143 { 00144 // Start the thread immediately. 00145 StartThread(lpStartAddress, lpParameter, completionEvent, 0); 00146 } 00147 00148 return threadHandle; 00149 } 00150 catch (...) 00151 { 00152 // Clean up if thread creation fails. 00153 CloseHandle(threadHandle); 00154 CloseHandle(completionEvent); 00155 00156 return nullptr; 00157 } 00158 } 00159 00160 00161 DWORD WINAPI ResumeThread(__in HANDLE hThread) 00162 { 00163 std::lock_guard<std::mutex> lock(pendingThreadsLock); 00164 00165 // Look up the requested thread. 00166 auto threadInfo = pendingThreads.find(hThread); 00167 00168 if (threadInfo == pendingThreads.end()) 00169 { 00170 // Can only resume threads while they are in CREATE_SUSPENDED state. 00171 assert(false); 00172 return (DWORD)-1; 00173 } 00174 00175 PendingThreadInfo& info = threadInfo->second; 00176 00177 // Start the thread. 00178 try 00179 { 00180 StartThread(info.lpStartAddress, info.lpParameter, info.completionEvent, info.nPriority); 00181 } 00182 catch (...) 00183 { 00184 return (DWORD)-1; 00185 } 00186 00187 // Remove this thread from the pending list. 00188 pendingThreads.erase(threadInfo); 00189 00190 return 0; 00191 } 00192 00193 00194 BOOL WINAPI SetThreadPriority(__in HANDLE hThread, __in int nPriority) 00195 { 00196 std::lock_guard<std::mutex> lock(pendingThreadsLock); 00197 00198 // Look up the requested thread. 00199 auto threadInfo = pendingThreads.find(hThread); 00200 00201 if (threadInfo == pendingThreads.end()) 00202 { 00203 // Can only set priority on threads while they are in CREATE_SUSPENDED state. 00204 assert(false); 00205 return false; 00206 } 00207 00208 // Store the new priority. 00209 threadInfo->second.nPriority = nPriority; 00210 00211 return true; 00212 } 00213 00214 VOID WINAPI Sleep(__in DWORD dwMilliseconds ) 00215 { 00216 SleepEx( dwMilliseconds, FALSE ); 00217 } 00218 00219 VOID WINAPI SleepEx(__in DWORD dwMilliseconds, BOOL in_bAlertable) 00220 { 00221 static HANDLE singletonEvent = nullptr; 00222 00223 HANDLE sleepEvent = singletonEvent; 00224 00225 // Demand create the event. 00226 if (!sleepEvent) 00227 { 00228 sleepEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, STANDARD_RIGHTS_ALL|EVENT_MODIFY_STATE); 00229 00230 if (!sleepEvent) 00231 return; 00232 00233 HANDLE previousEvent = InterlockedCompareExchangePointerRelease(&singletonEvent, sleepEvent, nullptr); 00234 00235 if (previousEvent) 00236 { 00237 // Back out if multiple threads try to demand create at the same time. 00238 CloseHandle(sleepEvent); 00239 sleepEvent = previousEvent; 00240 } 00241 } 00242 00243 // Emulate sleep by waiting with timeout on an event that is never signalled. 00244 DWORD dwResult = WaitForSingleObjectEx(sleepEvent, dwMilliseconds, in_bAlertable); 00245 assert( dwResult != -1 ); 00246 } 00247 } 00248 } 00249 00250 #endif
프로젝트를 등록하세요. 아무런 조건이나 의무 사항 없이 빠른 시작을 도와드리겠습니다.
Wwise를 시작해 보세요