我已经爱上了lambdas,不久之前我写了一个简单的包装器,它接受一个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;
}
Run Code Online (Sandbox Code Playgroud)
注意:是的我知道这不需要模板,可以愉快地使用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 << "foo\n"; return 42;} ));
}
Run Code Online (Sandbox Code Playgroud)
如果您现在检查pTask,start_task_proc您可以看到file并且line可以告诉您任务是从哪里开始的。
当然,您可以避免该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)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
244 次 |
| 最近记录: |