CreateThread for Windows 8 Metro

CreateThread for Windows 8 Metro

Rate This
  • Comments 22

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:

  • CreateThread
  • CREATE_SUSPENDED and ResumeThread
  • Partial support for SetThreadPriority  (see comments in the header for details)
  • Sleep
  • Thread local storage  (TlsAlloc, TlsFree, TlsGetValue, TlsSetValue, plus see header comments about TlsShutdown)

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.

  • Alecazam, I don't understand your point here.  There is no such thing as a thread handle or thread ID in the Windows Store programming model.  All the Win32 APIs that return or accept such values are no longer supported, so these concepts no longer exist.

    This emulation code provides an emulation of one method (CreateThread) that does return a 'thread handle', but this is an emulated handle, not a real Win32 thread handle.  It works exactly like a real thread handle in that you can block on it using any of the Win32 wait APIs, and it will be signalled as soon as the 'thread' has finished running, and you can CloseHandle on it when you are done using it, but it is not a real thread handle at the Win32 level, any more than this emulated CreateThread method creates a real Win32 thread  (actually, the 'thread handle' returned by the CreateThread emulation is a Win32 manual reset event).

    This distinction is unimportant, however, because the emulated handle works correctly with the emulated CreateThread, and you do not have access to any of the various Win32 API methods that use real thread handles, so what difference does it make whether the returned value is a 'real' thread handle or not?

  • Shawn, good stuff.

    I'm curious why you don't just use the Fls functions to replace Tls?  (eg. FlsAlloc for TlsAlloc).  Should be simpler and possibly faster.

  • I had various routines that would obtain the current thread handle and pull up data off of that.  Since your emulation returns the thread back to the pool after the task completes, legacy code does not expect to see the same "thread handle" (emulated or real) appear until CloseHandle is called on the "thread handle".  I'm only pointing out that the emulation isn't quite right for legacy code.   I know it's an event handle, I use the same approach.

  • I should clarify that my data was tied to thread id (and that is obtainable in a store app).  It's just the thread id of the thread in the thread pool.   I could change the legacy code to reference off the thread (event) handle, but I wanted to keep that code unchanged.

  • My legacy code is using GetThreadID.  Is there any way to have the code that is running on a thread know what it's handle is?

  • Jim, I looked briefly at trying to emulate the thread ID family of APIs, but obviously didn't get as far as actually doing that. My initial thought is this should be possible but will be quite subtle and in the end I just wasn't convinced how necessary it really was.  My experience is that most of the things you can do with thread IDs can also be done using thread local storage  (in fact, thread ID is most often used just as a building block for some kind of roll-your-own TLS equivalent).

    I'm curious what your code is using GetThreadID for?  Could this be changed to use TLS instead?

  • ...I am having issues on calling via C++ thread routine such as shown below

    where no compile error but p->f_iOnThreadProc() seems not calling.

    Please advise.

    //======================================================================================

    //MainPage.Xaml.h

    //

    namespace App1

    {

       public ref class MainPage sealed

       {

       ...

       static DWORD WINAPI fnThread (__in void* pv);

       int f_iOnThreadProc (void);

       ...

       };

    }

    //=======================================================================================

    // MainPage.Xaml.cpp

    //

    ...

    using namespace ThreadEmulation;

    ....

    DWORD WINAPI App1::MainPage::fnThread (__in void* pv)

    {

       App1::MainPage^                   p;

       p = reinterpret_cast<App1::MainPage^>(pv);

       p->f_iOnThreadProc(); // NOTE: No error, but f_iOnThreadProc() is not called.

       return 0;

    }

    int App1::MainPage::f_iOnThreadProc (void)

    {

       HRESULT                     hr;

       int                         x = 0;

       // lbx is Type Listbox

       lbx->Items->Append( "f_iOnThreadProc()...OK" );

       TextBlock^ tbx = ref new TextBlock();

       while( 1 )

       {

           hr = WaitForSingleObjectEx( m_hEvent, 512, TRUE );

           if (hr == WAIT_OBJECT_0)

               break;

           x++;

           tbx->Text = "cnt=[" + (x).ToString() +"]";

           // btnTest is Type Button.

           btnTest->Content = tbx;

       }

       return 0;

    }

    int App1::MainPage::f_iOnThreadOpen (void)

    {

       if( m_hEvent )

          return -1;

       m_hEven = CreateEventEx( nullptr, nullptr, CREATE_EVENT_INITIAL_SET, EVENT_ALL_ACCESS);

       if( m_hEvent == nullptr )

          return -1;

       if( m_hThread )

          return -1;

       m_hThread = CreateThread( 0x00,

                                 0,

                                 this->fnThread,

                                 reinterpret_cast<void*>(this),

                                 0,

                                 &m_dwThreadID ); // m_dwThreadID default to 0x00,

                                                  // assert(unusedThreadId == nullptr); is remarked under ThreadEmulation.cpp

       if (m_hThread == nullptr )

          return -1;

       return 0;

    }

Page 2 of 2 (22 items) 12
Leave a Comment
  • Please add 4 and 4 and type the answer here:
  • Post