我的代码是否导致死锁?我不知道。有人可以确认或否定吗?

问题描述 投票:0回答:1

对于我新工作的一个新项目,技术主管和架构师要求我学习和使用 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;
}

我运行了代码,有时一切正常,但有时,它只是挂起,什么也没有发生。

c++ multithreading boost-asio threadpool deadlock
1个回答
0
投票

是的。存在死锁的可能性是因为您在

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();
}

© www.soinside.com 2019 - 2024. All rights reserved.