Как пометить каждый поток с именованным токеном как можно быстрее в C ++? - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть требование учесть все потоки в C ++ / 17 'приложении, которое мы собираемся разработать;

Сам счетчик потоков является thread_local объектом, который хранит информацию о потоке и может сообщать о нейвернуться к основному модулю.

Проблема в том, что thread_local объекты должны вызываться из каждого потока, по крайней мере, один раз, чтобы их можно было даже построить (см .: Могу ли я иметь объект thread_local, который будет ctor / dtorвызывается при создании каждого потока, даже если он не используется? ).После этого он будет должным образом разрушен при выходе из потока.

Моя первоначальная мысль состоит в том, чтобы сделать такую ​​конструкцию:

thread_local thread_accounter_t thread_accounter; // This is main accounter object

void thread_started(std::string name, std::string function, std::string filename, int line)
{
   thread_accounter.thread_started(name, function, filename, line);
}
#define THREAD_STARTED(name) thread_started(name, __FUNCTION__, __FILE__, __LINE__)

Затем в каждом потоке используйте:

std::thread my_thread([](){
    THREAD_STARTED("example");
    // Do actual job
});

У этого способа есть очень сильный недостаток: он подвержен ошибкам.Каждый поток, который не использует макрос (т. Е. Из-за упущения), будет невидим для учета.

Моя следующая идея - наследовать std::thread и переопределять его конструктор.Таким образом, когда кто-то использует our::thread, он будет вынужден (конструктором) заполнять имя потока.Используя простые приемы, мы можем заставить пользователя не использовать std::thread.

class thread : public std::thread
{
   public:
       thread_t() noexcept {}
       thread_t( thread_t&& other ) noexcept : std::thread(std::move(other)) {}
       template<class function_t, class... args_t >

// Following constructor actually does not compile:
       explicit thread_t(std::string name, std::string function, std::string filename, int line, function_t&& f, args_t&&... args ) :
       std::thread(std::bind([name, function, filename, line](function_t&& f, auto&&... args){
           thread_started(name, function, filename, line);
           f(std::forward(args)...);
       }, std::move(f), std::move(args)...)) { }
       thread_t(const thread_t&) = delete;
};
#define THREAD_NAME(name) name, __FUNCTION__, __FILE__, __LINE__

. Затем просто используйте его:

thread my_thread(THREAD_NAME("sample thread"), [](){
    // Do actual job
});

Вопросы складываются в два раза:

1.) Если мой подход хорош, как я могу исправить конструктор thread, чтобы он компилировался?Минимальная выборка: https://pastebin.com/mNMpunMT

2.) Если мой подход можно исправить, как лучше это сделать?

1 Ответ

0 голосов
/ 06 декабря 2018

Пригвожден!

std::bind не требуется, поскольку конструктор std::thread может принимать произвольные аргументы.Итак, вот окончательная версия:

#include <iostream>
#include <thread>

void thread_started(std::string name, std::string function, std::string filename, int line)
{

}

class thread_t : public std::thread
{
   public:
       thread_t() noexcept {}
       thread_t( thread_t&& other ) noexcept : std::thread(static_cast<std::thread&&>(std::move(other))) {}
       template<class function_t, class... args_t >

       explicit thread_t(std::string name, std::string function, std::string filename, int line, function_t&& f, args_t&&... args ) :
       std::thread([name, function, filename, line](function_t&& f, auto&&... args){
           thread_started(name, function, filename, line);
           f(std::move(args)...);
       }, std::move(f), std::move(args)...) { }
       thread_t(const thread_t&) = delete;
};
#define THREAD_NAME(name) name, __FUNCTION__, __FILE__, __LINE__

int main()
{
    thread_t my_thread(THREAD_NAME("sample thread"), [](){
        // Do actual job
       std::cout << "Hello!";
    });
    std::cout << "Hello, world!\n";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...