Подтвердить что ты не робот

Как получить целочисленный идентификатор потока в С++ 11

С++ 11 имеет возможность получения текущего идентификатора потока, но он не поддается целочисленному типу:

cout<<std::this_thread::get_id()<<endl;

: 139918771783456

cout<<(uint64_t)std::this_thread::get_id()<<endl;

error: недопустимый листинг из типа 'std:: thread:: id для ввода' uint64_t такие же для других типов: invalid cast from type 'std:: thread:: id для ввода' uint32_t

Я действительно не хочу делать кастинг с указателем, чтобы получить идентификатор целочисленного потока. Есть ли разумный способ (стандартный, потому что я хочу, чтобы он был переносимым), чтобы сделать это?

4b9b3361

Ответ 1

Портативное решение - передать ваши собственные идентификаторы в поток.

int id = 0;
for(auto& work_item : all_work) {
    std::async(std::launch::async, [id,&work_item]{ work_item(id); });
    ++id;
}

Тип std::thread::id должен использоваться только для сравнения, а не для арифметики (т.е. как сказано на банке: идентификатор). Даже его текстовое представление, созданное operator<<, не указано, поэтому вы не можете полагаться на то, что оно представляет собой число.

Вы также можете использовать карту значений std::thread::id для своего собственного идентификатора и поделиться этой картой (с надлежащей синхронизацией) между потоками, а не передавать идентификатор напрямую.

Ответ 2

Вам просто нужно сделать

std::hash<std::thread::id>{}(std::this_thread::get_id())

чтобы получить size_t.

Из контекста:

Специализация шаблона std::hash для std::thread::id позволяет пользователям получать хэши идентификаторов потоков.

Ответ 3

Другим id (идея? ^^) будет использование stringstreams:

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());

И используйте try catch, если вы не хотите, чтобы исключение было в случае, если все пошло не так...

Ответ 4

Одной из идей было бы использовать локальное хранилище потоков для хранения переменной - не имеет значения, какой тип, если он соответствует правилам локального хранилища потоков, - затем использовать адрес этой переменной как свой "идентификатор потока" ". Очевидно, любая арифметика не будет иметь смысла, но она будет интегральным типом.

Для потомков: pthread_self() возвращает a pid_t и является posix. Это переносимо для определения портативного устройства.

gettid(), почти наверняка не переносимый, но он возвращает дружественное значение GDB.

Ответ 5

Я действительно не знаю, как быстро это происходит, но это решение, которое мне удалось выполнить:

const size_t N_MUTEXES=128;//UINT_MAX,not 128  for answer to my original question
hash<std::thread::id> h;
cout<<h(std::this_thread::get_id())%N_MUTEXES<<endl;

Снова я начинаю думать, что получить указатель на структуру и отбросить ее к unsigned int или uint64_t - это ответ... EDIT:

uint64_t get_thread_id()
{
    static_assert(sizeof(std::thread::id)==sizeof(uint64_t),"this function only works if size of thead::id is equal to the size of uint_64");
    auto id=std::this_thread::get_id();
    uint64_t* ptr=(uint64_t*) &id;
    return (*ptr);
}
int main()
{
    cout<<std::this_thread::get_id()<<"  "<<get_thread_id()<<endl;
}

static_assert для предотвращения адских проблем:) Переписывать легко по сравнению с поиском такого рода ошибок.:)

Ответ 6

Таким образом, следует работать:

std::stringstream ss;
ss << std::this_thread::get_id();
int id = std::stoi(ss.str());

Не забудьте включить библиотеку sstream

Ответ 7

thread::native_handle() возвращает thread::native_handle_type, который является typedef для long unsigned int.

Если поток создан по умолчанию, native_handle() возвращает 0. Если к нему присоединен поток ОС, возвращаемое значение ненулевое (это pthread_t в POSIX).

Ответ 8

это зависит от того, для чего вы хотите использовать thread_id; вы можете использовать:

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());

Это создаст уникальный идентификатор с вашим процессом; но есть ограничение: если вы запускаете несколько экземпляров одного и того же процесса, и каждый из них записывает свои идентификаторы потоков в общий файл, уникальность thread_id не гарантируется; на самом деле, скорее всего, у вас будут перекрытия. В этом случае вы можете сделать что-то вроде:

#include <sys/time.h>
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
uint64_t id = (ts.tv_sec % 1000000000) * 1000000000 + ts.tv_nsec;

теперь вам гарантируются уникальные идентификаторы потоков по всей стране.

Ответ 9

Может быть, это решение будет полезным для кого-то. Назовите это впервые im main(). Предупреждение: names растет бесконечно.

std::string currentThreadName(){
    static std::unordered_map<std::thread::id,std::string> names;
    static std::mutex mtx;

    std::unique_lock<std::mutex> lock(mtx);

    auto id = std::this_thread::get_id();

    if(names.empty()){
        names[id] = "Thread-main";
    } else if(names.find(id) == names.end()){
        std::stringstream stream;
        stream << "Thread-" << names.size();
        names[id] = stream.str();
    }

    return names[id];
}

Ответ 10

Другая альтернатива:

#include <atomic>

static std::atomic<unsigned long long> thread_counter;

unsigned long long thread_id() {
    thread_local unsigned long long tid = thread_counter++;
    return tid;
}

Сгенерированный код для этой функции g++ в 64-разрядной версии x86 просто:

_Z9thread_idv:
        cmp     BYTE PTR fs:[email protected], 0
        je      .L2
        mov     rax, QWORD PTR fs:[email protected]
        ret
.L2:
        mov     eax, 1
        lock xadd       QWORD PTR _ZL14thread_counter[rip], rax
        mov     BYTE PTR fs:[email protected], 1
        mov     QWORD PTR fs:[email protected], rax
        ret
_ZGVZ9thread_idvE3tid:
        .zero   8
_ZZ9thread_idvE3tid:
        .zero   8

Т.е. одна ветвь без какой-либо синхронизации, которая будет правильно предсказана, за исключением первого вызова функции. После этого просто один доступ к памяти без синхронизации.

Ответ 11

Основная причина не использовать thread :: get_id() заключается в том, что он не уникален для отдельной программы/процесса. Это потому, что идентификатор может быть повторно использован для второго потока, как только первый поток завершится.

Это кажется ужасной особенностью, но это то, что в С++ 11.