boostorg / mysql

MySQL C++ client based on Boost.Asio
https://www.boost.org/doc/libs/master/libs/mysql
Boost Software License 1.0
246 stars 34 forks source link

always collapsing, Can you tell me the reason? #271

Closed jphz closed 1 month ago

jphz commented 1 month ago
#include <iostream>

#include "boost/asio.hpp"
#include "boost/asio/spawn.hpp"
#include "boost/mysql/connection_pool.hpp"

int main() {
    boost::asio::thread_pool th_pool(10);
    boost::mysql::pool_params params{};
    params.server_address.emplace_host_and_port("localhost");
    params.username = "root";
    params.password = "123456";
    params.database = "boat";
    params.initial_size = 1;
    params.max_size = 100;
    static auto conn_pool = std::make_shared<boost::mysql::connection_pool>(
        boost::mysql::pool_executor_params::thread_safe(th_pool.get_executor()), std::move(params));

    conn_pool->async_run(boost::asio::detached);

    while (true) {
        for (int i = 0; i < 100; ++i) {
            boost::asio::spawn(boost::asio::make_strand(th_pool.get_executor()), [&](boost::asio::yield_context yield) {
                boost::system::error_code ec;
                boost::mysql::pooled_connection conn = conn_pool->async_get_connection(yield[ec]);
                if (ec) {
                    return;
                }

                static boost::mysql::diagnostics _errorInfo{};
                static boost::mysql::results _results{};
                conn->async_execute("SELECT COUNT(*) FROM `character`;", _results, _errorInfo, yield[ec]);
                if (ec) {
                    return;
                }

                for (auto rows : _results.rows()) {
                    for (std::size_t i = 0; i < rows.size(); ++i) {
                        auto field = rows[i];
                        std::cout << "async_execute:" << std::this_thread::get_id() << " : " << field.as_int64()
                                  << std::endl;
                    }
                }
            });
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    std::this_thread::sleep_for(std::chrono::seconds(100));
    th_pool.stop();
    conn_pool->cancel();
    return 0;
}
jphz commented 1 month ago

Access permission conflict image

jphz commented 1 month ago

Do you have multiple threads open internally?

jphz commented 1 month ago

I want to use multithreading, I have learned your code case, but it keeps crashing at the moment

anarthal commented 1 month ago

From your example, you have a single static variable shared between 100 coroutines, which is definitely causing trouble. I'll rewrite your example in some minutes.

anarthal commented 1 month ago

Making your variables non-static works as expected:

#include <iostream>

#include "boost/asio.hpp"
#include "boost/asio/spawn.hpp"
#include "boost/mysql/connection_pool.hpp"

int main()
{
    boost::asio::thread_pool th_pool(10);
    boost::mysql::pool_params params{};
    params.server_address.emplace_host_and_port("localhost");
    params.username = "root";
    params.password = "123456";
    params.database = "boat";
    params.initial_size = 1;
    params.max_size = 100;

    // No need to use static here
    auto conn_pool = std::make_shared<boost::mysql::connection_pool>(
        boost::mysql::pool_executor_params::thread_safe(th_pool.get_executor()),
        std::move(params)
    );

    conn_pool->async_run(boost::asio::detached);

    while (true)
    {
        for (int i = 0; i < 100; ++i)
        {
            boost::asio::spawn(
                // No need for a strand here, as you're no longer using static variables
                th_pool,
                [&](boost::asio::yield_context yield) {
                    boost::system::error_code ec;
                    boost::mysql::pooled_connection conn = conn_pool->async_get_connection(yield[ec]);
                    if (ec)
                    {
                        return;
                    }

                    // Don't use static variables here, as this causes a single variable
                    // to be used across all your coroutines, causing race conditions
                    boost::mysql::diagnostics _errorInfo{};
                    boost::mysql::results _results{};
                    conn->async_execute("SELECT COUNT(*) FROM `character`;", _results, _errorInfo, yield[ec]);
                    if (ec)
                    {
                        return;
                    }

                    for (auto rows : _results.rows())
                    {
                        for (std::size_t i = 0; i < rows.size(); ++i)
                        {
                            auto field = rows[i];
                            std::cout << "async_execute:" << std::this_thread::get_id() << " : "
                                      << field.as_int64() << std::endl;
                        }
                    }
                }
            );
        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    std::this_thread::sleep_for(std::chrono::seconds(100));
    th_pool.stop();
    conn_pool->cancel();
    return 0;
}
jphz commented 1 month ago

Thank you.