我需要考虑我们将要开发的C ++ / 17'应用程序中的所有线程;
线程会计iteself是thread_local
对象,用于保存有关线程的信息并能够将其报告回主模块。
问题是thread_local
对象需要从每个线程至少调用一次,才能被构造(请参阅:Can I have thread_local object which ctor/dtor will be called on each thread creation even if it is not used?)。之后,它将在线程退出时被正确破坏。
我最初的想法是进行这样的构造:
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。)如果我的方法可以纠正,那么更好的方法是什么?
答案 0 :(得分:0)
钉了!
由于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";
}