为连接对象创建shared_ptr时出现Boost-Mysql错误

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

我有以下代码,其中包含使用shared_ptr的boost::mysql连接。我想在应用程序运行时保留连接对象。我希望应用程序在运行时结束时关闭连接。但是,我在调试进程时遇到访问冲突。

class DatabaseProcess : public MainframeComponent
{
public:
    // MainframeComponent dispatch module type is set to Main because DatabaseProcess doesn't run on its own thread.
    DatabaseProcess(boost::asio::io_context &io_context) : _io_context(io_context), MainframeComponent(Horizon::System::RUNTIME_DATABASE) { }
    ~DatabaseProcess() 
    { 
        // Close connection object.
        if (_connection != nullptr) {
            _connection->close();
            _connection.reset();
        }

    }
    void initialize(int segment_number = 1) override { HLog(error) << "Database not configured"; }
    void initialize(int segment_number, std::string host, int port, std::string user, std::string pass, std::string database)
    {
        try {
            boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tls_client);
            _connection = std::make_shared<boost::mysql::tcp_ssl_connection>(_io_context.get_executor(), ssl_ctx);
            boost::asio::ip::tcp::resolver resolver(_io_context.get_executor());
            auto endpoints = resolver.resolve(host, std::to_string(port));
            boost::mysql::handshake_params params(user, pass, database);
            _connection->connect(*endpoints.begin(), params);
        } catch (boost::mysql::error_with_diagnostics &error) {
            HLog(error) << error.what();
        }

        bool value = _is_initialized;
        _is_initialized.compare_exchange_strong(value, true);
    }

    void finalize(int segment_number = 1) override 
    {
        bool value = _is_initialized;
        _is_initialized.compare_exchange_strong(value, false);
    }

    std::shared_ptr<boost::mysql::tcp_ssl_connection> get_connection() { return _connection; }

    bool is_initialized() { return _is_initialized.load(); }
protected:
    std::shared_ptr<boost::mysql::tcp_ssl_connection> _connection{nullptr};
    boost::asio::io_context &_io_context;
    std::atomic<bool> _is_initialized;
};

调试输出:


Running 1 test case...

*** No errors detected
Exception thrown at 0x00007FFA63663FAA (ntdll.dll) in ZoneSystemTest.exe: 0xC0000005: Access violation writing location 0x0000000000000024.
The program '[27192] ZoneSystemTest.exe' has exited with code 0 (0x0).

主要负责的线路是-

_connection = std::make_shared<boost::mysql::tcp_ssl_connection>(_io_context.get_executor(), ssl_ctx);

评论后,错误消失。是因为我们无法在连接对象的内存中创建资源吗?

c++ mysql boost shared-ptr
1个回答
0
投票

对象的生命周期没有得到很好的保护。

  • _io_context
    成员在基类之后初始化,您想要修复初始化程序的顺序以反映这一点

  • ssl_ctx
    initialize
    结束之前被破坏。它可能需要是一个成员对象

  • 您可能想在连接尝试中使用所有解析器端点:

         boost::asio::connect(_connection->stream().next_layer(), endpoints);
    
  • 最重要的是,

    io_context
    对象的生命周期没有显示出来,但需要加以保护。

通过避免引用、两步初始化和动态分配,一切都可以大大简化。

一些修复

上述部分已修复:

住在Coliru

#include <boost/asio.hpp>
#include <boost/mysql.hpp>

#include <iostream>
#include <syncstream>
#define HLog(level) (std::osyncstream(std::cout) << "\n[" #level "] ")

namespace Horizon::System {
    enum ModuleType {
        RUNTIME_DATABASE,
        RUNTIME_FILESYSTEM,
        RUNTIME_NETWORK,
        RUNTIME_PROCESS,
        RUNTIME_THREAD,
        RUNTIME_TIMER,
        RUNTIME_USER
    };
}

namespace asio = boost::asio;
namespace ssl  = asio::ssl;
using asio::ip::tcp;

struct MainframeComponent {
    MainframeComponent(Horizon::System::ModuleType module_type) : _module_type(module_type) {}

    virtual ~MainframeComponent()                   = default;
    virtual void initialize(int segment_number = 1) = 0;
    virtual void finalize(int segment_number = 1)   = 0;

    Horizon::System::ModuleType get_module_type() { return _module_type; }

  protected:
    Horizon::System::ModuleType _module_type;
};

class DatabaseProcess : public MainframeComponent {
  public:
    // MainframeComponent dispatch module type is set to Main because DatabaseProcess doesn't run on its own
    // thread.
    DatabaseProcess(asio::io_context& io_context)
        : MainframeComponent(Horizon::System::RUNTIME_DATABASE)
        , _io_context(io_context) {}

    ~DatabaseProcess() {
        // Close connection object.
        if (_connection != nullptr) {
            _connection->close();
            _connection.reset();
        }
    }

    void initialize(int /*segment_number*/ = 1) override { HLog(error) << "Database not configured"; }
    void initialize(int /*segment_number*/, std::string host, int port, std::string user, std::string pass,
                    std::string database) {
        try {
            _connection =
                std::make_shared<boost::mysql::tcp_ssl_connection>(_io_context.get_executor(), ssl_ctx);
            tcp::resolver                  resolver(_io_context.get_executor());
            auto                           endpoints = resolver.resolve(host, std::to_string(port));
            boost::mysql::handshake_params params(user, pass, database);
            // asio::connect(_connection->stream().next_layer(), endpoints);
            _connection->connect(*endpoints.begin(), params);
        } catch (boost::mysql::error_with_diagnostics& error) {
            HLog(error) << error.what();
        }

        bool value = _is_initialized;
        _is_initialized.compare_exchange_strong(value, true);
    }

    void finalize(int /*segment_number*/ = 1) override {
        bool value = _is_initialized;
        _is_initialized.compare_exchange_strong(value, false);
    }

    std::shared_ptr<boost::mysql::tcp_ssl_connection> get_connection() { return _connection; }

    bool is_initialized() { return _is_initialized.load(); }

  protected:
    asio::io_context&                                 _io_context;
    ssl::context                                      ssl_ctx{ssl::context::tls_client};
    std::shared_ptr<boost::mysql::tcp_ssl_connection> _connection{nullptr};
    std::atomic<bool>                                 _is_initialized;
};

int main() {
    //
    asio::io_context ioc;
    DatabaseProcess p(ioc);

    p.initialize(1, "localhost", 3306, "root", "root", "test");
}
© www.soinside.com 2019 - 2024. All rights reserved.