Shawn Hargreaves Blog
The WinRT programming environment, which is used to create Metro applications for Windows 8, replaces the old Win32 threading APIs such as CreateThread with a new ThreadPool::RunAsync API. This is generally a good thing (ThreadPool is better than CreateThread for several reasons) but it can be a pain when trying to port existing code that depends on those older APIs.
Porting shim to the rescue! This code emulates a subset of the Win32 threading APIs as a wrapper on top of WinRT ThreadPool:
Get it here: ThreadEmulation.zip
I recommend only using this for porting legacy code. When writing new Metro applications, it is better to directly use WinRT ThreadPool.
Oh. It looks so hard. Especially after Thread/BackgroundWorker in C#..
> It looks so hard
WinRT ThreadPool is very simple and easy to use.
This porting shim is for people who want to easily port legacy Win32 code, rather than easily write new WinRT code.
a nice sample once again
shawn can you explain or does this divide the workload on multiple cores
if not can you post a smaple on multiple cores, or point me in the right direction to find info on this
as i think that when the tablets comes it has multiple cores running as showen at your videos running the nvidia tablets
Shawn, PLEASE PLEASE PLEASE I want to port my XNA windws phone game to Win 8 metro. Will there be a XNA GS 5.0 with support for metro style apps?
although these api's are only for Metro apps,
"shawn can you explain or does this divide the workload on multiple cores"
That's what WinRT Threadpool was designed to do. If you want that, use it directly and you will get all the multi-core scalability. If apps decide to manage their threads directly, as in tradicional models, they need to do everything manually (and probably not get it right).
I was wondering if there is a function in WinRT that will tell me how many logical CPU are in the system (cores ( * 2 when hyperthreaded))
the reason I am asking is to avoid starting too many thread.
Rule of thumbs should me no more then 4 thread per CPU.
> the reason I am asking is to avoid starting too many thread.
This is exactly why it is better to use ThreadPool rather than managing your own legacy style long running threads! ThreadPool understands CPU utilization at a system wide level, and will only submit the appropriate number of work items for simultaneous execution, automatically batching things if you queue up more work than there are available CPU cores to execute it.
You can query the number of hardware cores from the NUMBER_OF_PROCESSORS environment variable, but this isn't enough to do proper thread scheduling for a couple of reasons:
- Some cores may be parked (switched off) to conserve power, and this could change at any time
- Some cores may be in use by other processes - you can't assume you always have exclusive access to all of them
ThreadPool is part of the OS, so it understands these situations and can respond appropriately. If you care about this level of efficiency, you should use ThreadPool, not try to build your own work management system on top of just a few long running threads.
I see that you have written several times that it is probably better to use ThreadPool than to "roll your own" threading framework. I have two questions:
1. Is ThreadPool native code, as in truly native, or is it some kind of semi-native wrapper framework?
2. There are a few of us who are quite comfortable with multi-threading. I wrote my first kernel-mode switcher for the iAPX 386 in 1989. For such people, pulling out CreateThread and forcing them to use something else is a bit abrupt. I can understand that Microsoft might have done this because they were worried that providing choice would have been insufficient to induce people to migrate. Whatever the reason, I think they should have left a choice. That said, do you see any possibility of exposing CreateThread and friends in the foreseeable future?
1) ThreadPool is a Windows kernel component, so yes, all native code. This functionality is exposed as a WinRT interface (ie a vtable containing pointers to code).
2) I don't work on the kernel/threading team who owns that decision, so I can't comment on what they might decide to do in the future. I do know they had good reasons for the decisions made for Win8 Store apps, though.
We're having to implement a thread wrapper for legacy code as well. Not only is it way too complex, but I see that your impl has the same problem as ours.
The thread pool recycles the thread handle as soon as the task completes. That differs from a real thread which stays valid until CloseHandle. We have legacy code that is tracking it's own data off the thread handle. When it see the same thread handle appear, it thinks that thread is being used before it's been released. There needs to be something to prevent the thread/task from going back to the thread pool (yet another event/waitforsingleobjectex at the end of the task).
Alcazam: my implementation handles the thread exit behavior just fine. The handle returned from the emulated CreateThread remains valid (and can be waited on) until the caller decides to call CloseHandle on it. This isn't tied to when the task completes (they are related because task completion will signal that handle, but it doesn't close it, which is exactly the same as the original Win32 thread behavior).
Thanks Shawn. I didn't realize that you could still wait on a thread handle under WinRT. I've done the DuplicateHandle like you od, but we've been tracking an event with each thread handle. When we get to a Wait, we wait on the event, and not the thread handle. The thought was that the thread handle never signals, because it's just thrown back into the pool.
There's still a need for the physical core count. Logical cores is already obtained from GetNativeSystemInfo. We have SIMD tasks that doesn't benefit from the 2x threads. The unfortunate aspect of a WinRT thread pool is not being able to require a physical core. We need some hinting mechanism to request that.
There isn't directly any such thing as a "thread handle" in WinRT - the actual threadpool task is a WinRT interface, not a Win32 handle at all. The handle returned by my CreateThread emulation is part of the emulation layer, not directly part of the WinRT threadpool implementation. So it's up to my emulation layer to make this work however I see fit (which in the case of this implementation was to copy the behavior of the Win32 CreateThread API).
The code still needed a wait at the end of the async task to prevent the thread from being returned to the thread pool. Otherwise elements that are tied to the thread handle or thread id get very confused when they see that same thread from the thread pool reused before CloseHandle has been hit. If you try to make your emulation return a threadID, you'll find that the code and suspended thread emulation become a lot more difficult (ie. Microsoft should be adding back this API).