使用 lambda 表达式构建线程
construction of thread using lambda expression
有人可以解释一下在下面的 lambda 函数中创建线程的位置吗?
使用的技术是什么?
有人可以推荐一个参考来理解语义吗?
我现在发布了完整的代码:
class ThreadPool {
public:
ThreadPool(size_t);
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args)
->std::future<typename std::result_of<F(Args...)>::type>;
~ThreadPool();
private:
// need to keep track of threads so we can join them
std::vector< std::thread > workers_m;
// the task queue
std::queue< std::function<void()> > tasks_m;
// synchronization
std::mutex queue_mutex_m;
std::condition_variable condition_m;
bool stop_m;
};
// the constructor just launches some amount of workers
inline ThreadPool::ThreadPool(size_t threads)
: stop_m(false)
{
std::thread::id id = std::this_thread::get_id();
for (size_t i = 0; i < threads; ++i)
{
workers_m.emplace_back(
[this]
{
for (;;)
{
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this- >queue_mutex_m);
std::thread::id id1 = std::this_thread::get_id();
this->condition_m.wait(lock, [this]{ return this->stop_m || !this->tasks_m.empty(); });
std::thread::id id = std::this_thread::get_id();
if (this->stop_m && this->tasks_m.empty())
return;
task = std::move(this->tasks_m.front());
this->tasks_m.pop();
}
task();
}
}
);
}
}
ThreadPool
s 构造函数使用 std::vector
的 emplace_back
函数在 workers_m
变量的后面构造一个 std::thread
。 emplace_back
与push_back
的不同之处在于,它通过转发传递给元素类型(std::thread
)的构造函数的参数来直接构造元素类型。另一方面,push_back
需要左值或临时元素类型,然后将其适当地复制或移动到向量的后面。
ThreadPool
的构造函数将在 for 循环中执行此操作以创建适当数量的工作线程,如构造函数参数 (threads
) 所指定。 std::thread
s constructors 之一接受一个可调用参数和任意数量的参数,并将 运行 该函数放在相应的线程上。在这种情况下,传入的 lambda 用于构造一个线程,该线程将 运行 只要需要(由 for(;;)
给定),获取互斥锁以授予对任务队列的独占访问权,并使用条件变量等待,直到设置停止标志,或者直到队列中有可用的东西。
一旦通知条件变量并且两个条件之一为真,线程就可以继续。但是,不知道这两个条件中的哪一个为真,因此检查
if (this->stop_m && this->tasks_m.empty())
return;
这似乎有点缺陷,因为如果设置 stop_m
工作线程应该停止处理任务,即使队列仍然包含要执行的任务。但是这个检查只会触发两个条件都为真。
如果上述检查为假,线程std::move
将要执行的任务移出队列,pop()
发送它,然后释放由unique_lock
由于锁的析构函数。然后线程通过调用它来执行任务。由于 for(;;)
循环
,然后重复此过程
有人可以解释一下在下面的 lambda 函数中创建线程的位置吗? 使用的技术是什么? 有人可以推荐一个参考来理解语义吗?
我现在发布了完整的代码:
class ThreadPool {
public:
ThreadPool(size_t);
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args)
->std::future<typename std::result_of<F(Args...)>::type>;
~ThreadPool();
private:
// need to keep track of threads so we can join them
std::vector< std::thread > workers_m;
// the task queue
std::queue< std::function<void()> > tasks_m;
// synchronization
std::mutex queue_mutex_m;
std::condition_variable condition_m;
bool stop_m;
};
// the constructor just launches some amount of workers
inline ThreadPool::ThreadPool(size_t threads)
: stop_m(false)
{
std::thread::id id = std::this_thread::get_id();
for (size_t i = 0; i < threads; ++i)
{
workers_m.emplace_back(
[this]
{
for (;;)
{
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this- >queue_mutex_m);
std::thread::id id1 = std::this_thread::get_id();
this->condition_m.wait(lock, [this]{ return this->stop_m || !this->tasks_m.empty(); });
std::thread::id id = std::this_thread::get_id();
if (this->stop_m && this->tasks_m.empty())
return;
task = std::move(this->tasks_m.front());
this->tasks_m.pop();
}
task();
}
}
);
}
}
ThreadPool
s 构造函数使用 std::vector
的 emplace_back
函数在 workers_m
变量的后面构造一个 std::thread
。 emplace_back
与push_back
的不同之处在于,它通过转发传递给元素类型(std::thread
)的构造函数的参数来直接构造元素类型。另一方面,push_back
需要左值或临时元素类型,然后将其适当地复制或移动到向量的后面。
ThreadPool
的构造函数将在 for 循环中执行此操作以创建适当数量的工作线程,如构造函数参数 (threads
) 所指定。 std::thread
s constructors 之一接受一个可调用参数和任意数量的参数,并将 运行 该函数放在相应的线程上。在这种情况下,传入的 lambda 用于构造一个线程,该线程将 运行 只要需要(由 for(;;)
给定),获取互斥锁以授予对任务队列的独占访问权,并使用条件变量等待,直到设置停止标志,或者直到队列中有可用的东西。
一旦通知条件变量并且两个条件之一为真,线程就可以继续。但是,不知道这两个条件中的哪一个为真,因此检查
if (this->stop_m && this->tasks_m.empty())
return;
这似乎有点缺陷,因为如果设置 stop_m
工作线程应该停止处理任务,即使队列仍然包含要执行的任务。但是这个检查只会触发两个条件都为真。
如果上述检查为假,线程std::move
将要执行的任务移出队列,pop()
发送它,然后释放由unique_lock
由于锁的析构函数。然后线程通过调用它来执行任务。由于 for(;;)
循环