对于我新工作的一个新项目,技术主管和架构师要求我学习和使用 boost::asio。具体来说是库的 thread_pool 类。
让我把事情放在上下文中。 我们正在构建一个可以进行复杂计算的应用程序。用户发送一个 XML 作为输入,其中包含我们需要的所有数据,而我正在开发的项目应该采用该 XML,检索它需要的所有信息,然后启动并执行一堆计算。最后,必须将结果发送回用户。这一切都是异步完成的。
现在,架构师希望该项目成为一个接受用户请求的微服务。 为了进行尽可能多的计算,我们应该有一个计算器线程池。
每个线程都会深入用户的请求队列。进行计算,返回结果,如果队列不为空,则接受下一个请求。为了实现这一目标,选择了 Boost Asio。所以,我的问题确实是针对 Boost Asio 的。我们不打算改变这个工具。 Boost asio包含一个类thread_pool,似乎就是为了解决这类问题而设计的。
我仍处于开始阶段,我试图看看它是如何工作的。不幸的是,即使我今天写的这个简单的代码似乎也不能一直工作。有时它有效,有时它挂起并且什么也没有发生......这对我来说是僵局的迹象。我不确定。
您能告诉我有什么问题吗? 干杯,
#include <boost/asio/post.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/use_future.hpp>
#include <cstdlib>
#include <exception>
#include <future>
#include <iostream>
#include <mutex>
#include <thread>
int main()
{
boost::asio::thread_pool pool{5};
std::mutex mutex;
for(int i = 0; i < 5; ++i)
{
boost::asio::post(pool, [i, &mutex]() {
try
{
std::lock_guard<std::mutex> lg{mutex};
std::cout << "Task " << i << " executed by thread " << std::this_thread::get_id()
<< std::endl;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
});
}
std::future<int> r1 = boost::asio::post(pool, boost::asio::use_future([]() { return 2; }));
{
std::lock_guard<std::mutex> lg{mutex};
std::cout << "Result = " << r1.get() << '\n';
}
// Optional: Wait for all tasks to complete
pool.join();
return EXIT_SUCCESS;
}
我运行了代码,有时一切正常,但有时,它只是挂起,什么也没有发生。
是的。存在死锁的可能性是因为您在
main
: r1.get()
中对未来进行了阻塞等待,同时持有控制台输出互斥体。如果您在锁外等待,则死锁的可能性就消失了:Live On Coliru:
r1.wait();
{
std::lock_guard<std::mutex> lg{console_mx};
std::cout << "Result = " << r1.get() << '\n';
}
注意,使用
std::osyncstream
可以完全避免陷阱:Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
#include <syncstream>
namespace asio = boost::asio;
static thread_local unsigned const thread_id = [] {
static std::atomic<unsigned> id = 0;
return id++;
}();
static auto out() { return std::osyncstream{std::cout}; }
int main() {
asio::thread_pool pool{5};
for (int i = 0; i < 5; ++i)
post(pool, [i] { out() << "Task " << i << " executed by thread " << thread_id << std::endl; });
std::future<int> r1 = post(pool, asio::use_future([]() { return 2; }));
// r1.wait();
out() << "Result = " << r1.get() << '\n';
pool.join();
}