跟踪线程创建点以进行调试

我爱上了lambda,而前一段时间,我写了一个简单的包装,它需要一个lambda并在新线程上启动它。

//
// Starts a task on a separate thread, when passed a lambda expression
//
template<typename T>
smart_ptrs::w32handle StartTask(T f)
{
    // Make a copy of the task on the heap
    T* pTask = new T(f);

    // Create a new thread to service the task
    smart_ptrs::w32handle hThread(::CreateThread(
        NULL, 
        0, 
        (LPTHREAD_START_ROUTINE)& detail::start_task_proc<T>, 
        (LPVOID) pTask, 
        NULL, 
        NULL)); 

    // If the caller ignores this rc, the thread handle will simply close and the
    // thread will continue in fire-and-forget fashion.
    return hThread;
}

:是的,我知道这并不真的需要一个模板,并可以愉快地使用std::function 。 我已经这样发布它,因为它匹配了我必须成为模板的更复杂(异步队列)版本。

最终的结果是一个非常容易在并行算法中使用的函数等。但是,如果您开始广泛使用这样的函数,则会出现问题。 因为创建的所有线程似乎都来自相同的通用函数,所以很难说明它们在代码中的起始位置。 通常可以从他们正在做的事情的上下文中得出结论,但它不像使用显式的线程函数那样容易。 有没有人有一个很好的方法来标记这些线程,以便更容易调试?


据我可以从代码中知道,你会有线程,其中有一个start_task_proc在调用堆栈的某个地方调用它们的函数对象。 您可以修改该函数以获取指向“任务信息”结构的指针,而不是裸函数对象。 您可以将任何您喜欢的信息填充到信息对象中,例如您创建任务的行号和文件名:

template <class T>
struct TaksInfo {
  T func;
  unsigned line;
  char const* file;

  TaskInfo(T&& t, unsigned l, char const* f)
    : func(std::move(t), line(l), file(f) {}
};


template<typename T>
smart_ptrs::w32handle StartTask(T f, unsigned line, char const* file)
{
    // Make a copy of the task on the heap
    auto pTask = new TaskInfo<T>(f, line, file);

    // Create a new thread to service the task
    smart_ptrs::w32handle hThread(::CreateThread(
        NULL, 
        0, 
        (LPTHREAD_START_ROUTINE)& detail::start_task_proc<T>, 
        (LPVOID) pTask, 
        NULL, 
        NULL)); 

    // If the caller ignores this rc, the thread handle will simply close and the
    // thread will continue in fire-and-forget fashion.
    return hThread;
}

#define START_TASK(f) StartTask(f, __LINE__, __FILE__)

template <class T>
DWORD start_task_proc(LPVOID lpParameter) {
  auto pTask = (TaskInfo<T>*) lpParameter;
  return pTask->func();
}


//use:
int main() {
  auto threadHandle = START_TASK(([]() -> DWORD { std::cout << "foon"; return 42;} ));
}

如果你现在在start_task_proc检查pTask ,你可以看到fileline可以告诉你任务开始的位置。
当然,您可以避免TaskInfo结构,并将信息仅作为start_task_proc的模板参数:

template <class T, unsigned Line, char const* File>
DWORD start_task_proc(LPVOID lpParameter) { /* as you have it */)

template<unsigned Line, char const* File, typename T> //use T last fur type deduction
smart_ptrs::w32handle StartTask(T f)
{
    // Make a copy of the task on the heap
    auto pTask = new T(std::move(f));

    // Create a new thread to service the task
    smart_ptrs::w32handle hThread(::CreateThread(
        NULL, 
        0, 
        (LPTHREAD_START_ROUTINE)& detail::start_task_proc<T, Line, File>,   //!!!
        (LPVOID) pTask, 
        NULL, 
        NULL)); 

    // If the caller ignores this rc, the thread handle will simply close and the
    // thread will continue in fire-and-forget fashion.
    return hThread;
}

#define START_TASK(f) StartTask<__LINE__, __FILE__>(f)
链接地址: http://www.djcxy.com/p/13837.html

上一篇: Tracing thread creation points for debugging

下一篇: Android: ActionBar, TabListener and support.v4.Fragment