Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the ID of a boost::thread for PostThreadMessage

I have a Visual Studio 2008 C++ project using Boost 1.47.0 where I need to get the native Windows ID of a boost::thread to pass to PostThreadMessage.

In Windows Vista and 7, I would just do this:

DWORD thread_id = ::GetThreadId( mythread.native_handle() );

This is fine, but I also need my app to work in XP where GetThreadId does not exist.

I have found that boost:thread stores the thread ID value in boost::thread::id's private data member thread_data. I can get to that by doing some nasty casts:

boost::detail::thread_data_base* tdb = *reinterpret_cast< boost::detail::thread_data_base** >( &message_thread.get_id() );
DWORD thread_id = tdb->id;

But, I start getting compiler warnings for referencing a temporary boost::thread::id object.

warning C4238: nonstandard extension used : class rvalue used as lvalue

Is there a good way to get the ID? It is very frustrating to see the piece of data I need, but not be able to get at it.

Thanks, PaulH

like image 392
PaulH Avatar asked Feb 27 '12 22:02

PaulH


1 Answers

Here's a clever/nasty hack using a technique described by Johannes Schaub - litb on his blog, Access to private members: Safer nastiness. All credit should go to Johannes. I'll take the blame for applying it to a real-world scenario (or maybe you can):

#include <windows.h>
#include <iostream>

#include "boost/thread.hpp"

using namespace std;


// technique for accessing private class members
//
//  from: http://bloglitb.blogspot.com/2011/12/access-to-private-members-safer.html
//

template<typename Tag, typename Tag::type M>
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};

struct thread_data_f {
    typedef unsigned boost::detail::thread_data_base::*type;

    friend type get(thread_data_f);
};

struct thread_id_f {
    typedef boost::detail::thread_data_ptr boost::thread::id::*type;

    friend type get(thread_id_f);
};

template struct Rob<thread_data_f, &boost::detail::thread_data_base::id>;
template struct Rob<thread_id_f, &boost::thread::id::thread_data>;

unsigned int get_native_thread_id( boost::thread const& t)
{
    boost::detail::thread_data_ptr thread_data = t.get_id().*get(thread_id_f());
    unsigned thread_id = (*thread_data).*get(thread_data_f());

    return thread_id;
}

//
//
//


// test of get_native_thread_id()


void thread_func()
{
    cout << "thread running..." << endl;

    cout << "Windows says my ID is: " << GetCurrentThreadId() << endl;

    for (;;) {
        boost::this_thread::yield();
    }
}


int main()
{
    boost::thread t(thread_func);

    ::Sleep(2000);

    cout << "boost says my thread ID is: " << get_native_thread_id(t) << endl;

    return 0;
}

I'm not sure if this qualifies as a "good way" to get the info. But it works without modifying the boost headers or libraries, and the compiler doesn't complain at all - even with relatively high warnings. Tested on:

  • MinGW 4.6.1 -Wall -Wextra with a few especially noisy warnings turned off - but not for this test in particular. They're turned off in my generic 'compile this test' script.
  • VC++ 2008 and 2010 with /W4

Here a sample run that shows it works:

C:\temp>test
thread running...
Windows says my ID is: 5388
boost says my thread ID is: 5388

Of course, it should go without saying that this might break if/when boost::thread changes over time, but probably not silently.


Some explanatory notes/pointers:

The 'loophole' used in this technique is in C++03 14.7.2/8 "Explicit instantiation":

The usual access checking rules do not apply to names used to specify explicit instantiations. [Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible.]

Dave Abrahams has a 'gist' that uses similar techniques along with comments that explain pretty nicely what's going on:

  • https://gist.github.com/1528856

I found that in a comment he left on a previous article about private member access on Johannes' blog: Access to private members. That's easy!

like image 136
Michael Burr Avatar answered Oct 31 '22 13:10

Michael Burr