用于添加线程名称和堆栈大小的 std::thread helper 类

问题描述

我想创建一个辅助类(或 std::thread 的子类)以允许设置堆栈大小以及线程名称。 如果线程在不支持的平台上运行,例如堆栈大小,这个数字应该被忽略。

我在想一个“ThreadHelper”,它具有扩展的构造函数接口,并且只返回一个 std::thread。

老实说,我对 std::thread 包含的所有模板内容几乎没有经验。

现在线程类实例化如下: m_thread = new std::thread(&Button::Process,this); 我想要类似的东西: m_thread = new ThreadHelper.Create(&Button::Process,this,stackSize,name);

感谢任何建议。

谢谢 马丁

解决方法

您可以这样做: 您需要一个围绕线程启动函数的包装器,以便您可以在线程函数运行之前(也可能是之后)调用适当的函数。包含一个 try-catch 块并进行一些错误处理也可能是一个好主意。

template <typename ThreadStartFnc>
struct ThreadWrapper
{
   ThreadStartFnc fnc;
   const char *name;     // (1) Note: careful,just a pointer here,not a string. See below.
   size_t priority;
   size_t stack_size;

   ThreadWrapper(...) // constructor here...

   void operator()()
   {
      SetThreadName(name);         // Whatever that is on your system
      SetThreadPriority(priority); // dito
      SetStackSize(stack_size);    // not all systems allow this
      try {
         fnc();
      }
      catch(...) {
         cerr << "Exception caught"; // Do exception processing here.
      }
   }
};

并且您需要一种简单的方法来实例化带有“插入”包装器的 std::thread,如下所示:

template <typename Fnc>
std::thread make_thread(const Fnc& f,const char *name,size_t priority=0,size_t stack_size=0)
{
   return std::thread(ThreadWrapper<Fnc>(f,name,priority,stack_size));
}

基本上就是这样。 std::thread 接受一个 Functor 对象,这就是 ThreadWrapper 。它调用 Functor() 来启动线程,也就是 void operator()()。此函数使用附加参数 name、priority、stack_size 来设置所有内容,然后调用您的函数。

使用 C++11/14/17 好东西(如可变参数模板参数和/或 lambda 函数,随心所欲地增强它。

下面是我们使用的实际包装函数(虽然我们没有使用 Functor,但我们使用 boost::bind 和一个静态模板函数代替)。

    template <typename Fnc>
    static inline void run_cstr(const Fnc &f,DWORD priority)
    {
        int rc=_configthreadlocale(0);
/*
        _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
        setlocale(LC_ALL,"C");
*/
        SetThreadName(name);
        watchdog::set_thread_info(name);
        ::SetThreadPriority(::GetCurrentThread(),priority);
        _set_se_translator(&_se_translator);
        _set_invalid_parameter_handler(&my_invalid_parameter_handler);
        __try {
            f();
        }
        __except (global_seh_handler(GetExceptionCode(),GetExceptionInformation()) ) {
        }
    }

它为 Visual Studio 设置 ThreadName (SetThreadName),设置区域设置,设置线程优先级,将我们的软件看门狗连接到线程,并为所有异常设置全局 Windows try/catch 处理程序,包括访问冲突等。 .. 如果任何未捕获的异常(包括无效的 std lib 参数)在此处结束,global_seh_handler 将被执行。它将编写我们用于事后调试的故障转储文件。

(1) 注意:我使用了 const char *name 作为线程名称,因为我假设线程将立即运行,而线程名称的字符串仍然可用。如果您将 ThreadWrapper 类型的对象存储更长的时间,那实际上是不安全的。那么您需要将 const char* 更改为 std::string