18

In the following code snippet,

void foo() {
  std::this_thread::native_handle().... //error here
}

int main() {
  std::thread t1(foo);

  t1.join();
  return 0;
}

How do you get the native_handle from std::this_thread from within the function foo?

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
pyCthon
  • 11,746
  • 20
  • 73
  • 135

5 Answers5

15

There is no way for a thread to autonomously gain access to its own std::thread. This is on purpose since std::thread is a move-only type.

I believe what you're requesting is a native_handle() member of std::thread::id, and that is an interesting suggestion. As far as I know it is not currently possible. It would be used like:

void foo()
{
    auto native_me = std::this_thread::get_id().native_handle();
    // ...
}

It wouldn't be guaranteed to work, or even exist. However I imagine most POSIX platforms could support it.

One way to try to change the C++ standard is to submit issues. Here are directions on how to do so.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 1
    do you think something like this is worth submitting as a proposal for C++14? – pyCthon Apr 28 '13 at 03:49
  • 1
    @NicholasPezolano: At this time no. However I could be persuaded by a motivating use case and an implementation demonstrating it. I.e. I think I know the cost/risk. But I don't think I know the benefit. If the benefit is zero, then no matter how low the cost, the benefit/cost ratio is poor. So you would need to demonstrate a large benefit. – Howard Hinnant Apr 29 '13 at 02:30
  • 3
    I don't think the OP necessarily wants `std::thread::id::native_handle`. I think the interesting point is: shouldn't the interface of `std::this_thread` mimic that of `std::thread`? Except of course for those members that relate to thread lifetime management, which as you rightfully point out doesn't make too much sense. That doesn't leave much, but `native_handle` strikes me as conspicuously absent. – Luc Danton Apr 30 '13 at 04:13
  • @HowardHinnant I wanted to make a cross platform thread profiler/debugger,this would simplify things greatly, i'm sure that does not qualify as a large benefit however. – pyCthon Apr 30 '13 at 04:18
  • 2
    @NicholasPezolano: It might, don't sell yourself short. My point is that to sell something to the committee, it helps for them to see *why* something is needed. It doesn't help nearly as much when you just say: why don't we do this. I've personally never made a cross platform thread profiler/debugger. So I'm clueless how this would simplify things greatly. But I find myself wishing I knew. A paper authored by yourself explaining things in more detail might motivate the committee. Or it might not. It is hard to predict the future. – Howard Hinnant Apr 30 '13 at 17:48
  • 2
    Why not `std::this_thread::native_handle()`, just like it's with `get_id()`? This can be treated as "completion" - both things are available in all thread systems, both things do the same logically. If there's something wrong with `this_thread::native_handle()`, the same can be said about `std::thread::native_handle()`. You need motivating use case? Think about debugging. Gdb won't show you a list of thread with ID's returned by `this_thread::get_id()`. – Ethouris Apr 12 '16 at 15:47
  • see also https://stackoverflow.com/a/74832738/119609 – Vladimir Ulchenko Dec 17 '22 at 11:54
9

C++11 does not provide a mechanism for getting the current threads native_handle. You must use platform specific calls, i.e. GetCurrentThread() on Windows:

void foo()
{
    auto native_me = ::GetCurrentThread();
}
chrisvarnz
  • 439
  • 7
  • 17
  • 9
    Can't vote for my own post, but laughed out loud when I hit this problem again and came across this answer! – chrisvarnz Sep 14 '18 at 13:37
2

As Howard pointed, there is no support for this in ISO C++ yet.

But thread::id has an overloaded operator<< to print itself to an ostream.

#include <iostream>
#include <thread>

int main()
{
    std::cout << "Current thread ID: " << std::this_thread::get_id() << std::endl;
}

Without knowing the semantics of the actual value (which is highly platform-dependent), printing it or using it as a key in a map is the most you should be doing anyway.

rustyx
  • 80,671
  • 25
  • 200
  • 267
0

Currently(C++17) you can't get native_handle from std::this_thread

The most possible interface might be std::this_thread::native_handle(). But not std::this_thread::get_id().native_handle(); by @Howard

Since Win/Linux/MacOS implement thread and thread::id differently: (below is informal pseudo code)

  • On Linux native_handle is stored at thread._M_id(of type id)._M_thread.
  • On Windows native_handle is stored at thread._Thr(of type _Thrd_t, not of type id)._Hnd.
  • On MacOS native_handle is stored at thread.__t_.

As you can see only in Linux source there is native_hanlde object implemented in thread::id structure. Thus on Win/MacOS you can't get the native_handle from an id object.

Finally, if your code runs only in Linux, there is a dirty trick to get native_handle from this_thread which I will never recommend:

auto thread_id = std::this_thread::get_id();
auto native_handle = *reinterpret_cast<std::thread::native_handle_type*>(&thread_id);
Charles
  • 115
  • 1
  • 8
0

In fact, there is one funny way to circumvent the problem and access it via std::thread , which may work in some cases. The original example was posted on this blog. I rewritten it. You can save the code below to test.cpp and compile & run it :

// g++ ./test.cpp  -lpthread && ./a.out
// 
#include <thread>
#include <vector>
#include <iostream>
#include <mutex>
#include <sched.h>
#include <pthread.h>
int main(int argc, const char** argv) {
  constexpr unsigned num_threads = 4;
  // A mutex ensures orderly access to std::cout from multiple threads.
  std::mutex iomutex;
  std::vector<std::thread> threads(num_threads);
  for (unsigned i = 0; i < num_threads; ++i) {
    threads[i] = std::thread([&iomutex, i,&threads] {
      // Create a cpu_set_t object representing a set of CPUs. Clear it and mark
      // only CPU i as set.
      cpu_set_t cpuset;
      CPU_ZERO(&cpuset);
      CPU_SET(i, &cpuset);
      int rc = pthread_setaffinity_np(threads[i].native_handle(),
                                      sizeof(cpu_set_t), &cpuset);
      if (rc != 0) {
        std::cerr << "Error calling pthread_setaffinity_np: " << rc << "\n";
      }
      std::this_thread::sleep_for(std::chrono::milliseconds(20));
      while (1) {
        {
          // Use a lexical scope and lock_guard to safely lock the mutex only
          // for the duration of std::cout usage.
          std::lock_guard<std::mutex> iolock(iomutex);
          std::cout << "Thread #" << i << ": on CPU " << sched_getcpu() << "\n";
        }

        // Simulate important work done by the tread by sleeping for a bit...
        std::this_thread::sleep_for(std::chrono::milliseconds(900));
      }
    });


  }

  for (auto& t : threads) {
    t.join();
  }
  return 0;
}
Y00
  • 666
  • 1
  • 7
  • 23