gpt4 book ai didi

c++ - boost::asio::ssl 多线程应用程序访问冲突

转载 作者:行者123 更新时间:2023-11-28 00:41:30 30 4
gpt4 key购买 nike

我创建了一个程序,该程序利用 boost 的 ssl 实现来使用 async_read_some()async_write_some() 向远程服务器发送和接收小数据包。读取和写入被包裹在一个链中以防止并发读取和写入。此外,我为每个创建的包装函数都包含一个互斥锁,以进一步防止并发访问(可能有点过分,但不会造成伤害)。写入存储在写入队列中,当线程收到数据可用的通知时,写入队列将被发送。

我遇到的问题发生在按顺序执行大量写入时,会导致各种错误,例如 Second Chance Assertion Failed 和 Access Violation。我还收到“解密失败或错误记录 mac”的读取错误。

根据我目前所做的研究,我发现如果同时执行读取和写入,SSL 套接字可能会损坏 - 至少根据讨论 herehere OP的症状与我的非常相似。他还说他使用的那条线不起作用,但我不明白他的解决方案。这对于我因尝试使用防止并发读写的方法而遇到的问题是有意义的。

我一直在使用的解决方法是限制顺序写入,以便每个写入之间至少有 20 毫秒的间隔。低于这个,我就会开始出错。不过,此解决方法不是很好,因为在某些时候可能仍然存在导致错误的并发读/写。

这是我的读/写代码的摘要:

void client::write(std::string message, char packetType) {
boost::lock_guard<boost::shared_mutex> lock(writeInProgressMutex);

std::string preparedMessage = prepareWrite(message, packetType);
char data_sent[2048];

for(std::string::size_type i = 0; i < preparedMessage.size(); ++i) {
data_sent[i] = preparedMessage[i];
if (i + 1 == preparedMessage.size()) {
data_sent[i+1] = NULL;
}
}

socket_->async_write_some(boost::asio::buffer(data_sent), strand_.wrap(boost::bind(&client::handle_write, this, boost::asio::placeholders::error)));
}

void client::read() {
boost::lock_guard<boost::shared_mutex> lock(readInProgressMutex);
socket_->async_read_some(boost::asio::buffer(data_), strand_.wrap(boost::bind(&client::handle_read, this, boost::asio::placeholders::error)));
}

我试验过不同类型的互斥体,所以我认为这不是问题所在。如果有人知道确保我的链正常工作的方法,或者您可以在我的代码/设计中看到一些明显的错误,请告诉我!

最佳答案

简而言之,验证对 client::write()client::read() 的所有调用都在 strand_ 中运行。如果没有额外的代码,同步结构(例如互斥锁)将无法有效地防止并发操作被调用。


ssl::stream thread safety 的 Boost.Asio 文档强调 strand 要求:

Distinct objects: Safe.

Shared objects: Unsafe. The application must also ensure that all asynchronous operations are performed within the same implicit or explicit strand.

如果 ssl::stream 操作仅在单个线程中调用,那么它是安全的,因为它们在隐式链中运行。另一方面,如果多个线程在 ssl::stream 上调用操作,则它们必须与链显式同步。由于没有引入自定义的中间处理程序,其他同步构造(例如互斥锁)将无效 asio_handler_invoke功能。

这是一个流程图,显示了异步写入链的必要链用法:

void client::start_write_chain()
{
strand_.post(boost::bind(&client::write, ...)) ---.
} .----------------------------------------------'
| .-------------------------------------------.
V V |
void client::write(...) |
{ |
... |
socket_->async_write_some(buffer, strand_.wrap( |
boost::bind(&client::handle_write, ...))); --. |
} .--------------------------------------------' |
V |
void client::handle_write( |
boost::system::error_code& error, |
std::size_t bytes_transferred) |
{ |
// If there is still data remaining. |
if (bytes_transferred < all_data) |
write(...); -----------------------------------'
}

此要求是 ssl::stream 异步操作根据组合操作实现的实现细节的结果。初始操作可能发生在调用者的上下文中,因此需要从 strand_ 中调用 client::write()。这些组合操作可能会导致对 socket_ 的许多中间调用。由于这些中间调用不知道 writeInProgressMutex,因此互斥体无法有效保护 socket_。考虑阅读 this有关组合操作和 strands 的更多详细信息,请回答。

此外,在 client::write() 中,缓冲区 data_sent 的生命周期未能满足 ssl::stream::async_write_some() 的要求,其中指出:

Although the buffers object may be copied as necessary, ownership of the underlying buffers is retained by the caller, which must guarantee that they remain valid until the handler is called.

在这种情况下,data_sent 的生命周期在 client::write() 返回时结束,这可能发生在调用完成处理程序之前。

关于c++ - boost::asio::ssl 多线程应用程序访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18656919/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com