我有以下代码,其中包含使用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);
评论后,错误消失。是因为我们无法在连接对象的内存中创建资源吗?
对象的生命周期没有得到很好的保护。
_io_context
成员在基类之后初始化,您想要修复初始化程序的顺序以反映这一点
ssl_ctx
在initialize
结束之前被破坏。它可能需要是一个成员对象
您可能想在连接尝试中使用所有解析器端点:
boost::asio::connect(_connection->stream().next_layer(), endpoints);
最重要的是,
io_context
对象的生命周期没有显示出来,但需要加以保护。
通过避免引用、两步初始化和动态分配,一切都可以大大简化。
上述部分已修复:
#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");
}