我有一些使用Boost的SSL ASIO库的多线程代码。代码是多线程的,但是每个SSL连接都有一个互斥锁,并且持有互斥锁的async_*
函数调用完成。
我有时会看到我的代码停滞不前。有一个卡住的线程。线程卡在bio_write
中。
堆栈跟踪看起来像这样:
#0 0x00000000010a974f in bio_write ()
#1 0x00000000010a3529 in BIO_write ()
#2 0x000000000105fe72 in ssl3_write_pending ()
#3 0x0000000001060b02 in ssl3_write_bytes ()
#4 0x0000000000cce43a in boost::asio::ssl::detail::engine::do_write
(this=0x1e618a0, data=0x234c7b0, length=189) at
/usr/include/boost/asio/ssl/detail/impl/engine.ipp:294
#5 0x0000000000cce109 in boost::asio::ssl::detail::engine::perform(this=0x1e618a0, op=(int
(boost::asio::ssl::detail::engine::*)(boost::asio::ssl::detail::engine *
const, void *, std::size_t)) 0xcce3fc<boost::asio::ssl::detail::engine::do_write(void*, unsigned long)>,
data=0x234c7b0, length=189, ec=..., bytes_transferred=0x7fff8ad74d48) at
/usr/include/boost/asio/ssl/detail/impl/engine.ipp:219
#6 0x0000000000ccdd23 in boost::asio::ssl::detail::engine::write
(this=0x1e618a0, data=..., ec=..., bytes_transferred=@0x7fff8ad74d48: 0) at
/usr/include/boost/asio/ssl/detail/impl/engine.ipp:137
#7 0x0000000000dac504 in boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>::operator()
(this=0x7fff8ad74d20, eng=..., ec=..., bytes_transferred=@0x7fff8ad74d48: 0)
at /usr/include/boost/asio/ssl/detail/write_op.hpp:51
#8 0x0000000000da9d8a in boost::asio::ssl::detail::io_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> >,
boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>,
boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t,
boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer,
boost::system::error_code const&, unsigned long>,
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1>
(*)(), boost::arg<2> (*)()> > > >::operator() (this=0x7fff8ad74d10, ec=...,
bytes_transferred=0, start=1) at /usr/include/boost/asio/ssl/detail/io.hpp:136
#9 0x0000000000da7f42 in boost::asio::ssl::detail::async_io<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> >,
boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>,
boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t,
boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer,
boost::system::error_code const&, unsigned long>,
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1> (*)(),
boost::arg<2> (*)()> > > > (next_layer=..., core=..., op=...,
handler=...) at /usr/include/boost/asio/ssl/detail/io.hpp:322
#10 0x0000000000da634d in
boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> >
>::async_write_some<boost::asio::mutable_buffers_1,
boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t,
boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer,
boost::system::error_code const&, unsigned long>,
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1>
(*)(), boost::arg<2> (*)()> > > > (this=0x1e61880, buffers=..., handler=...)
at /usr/include/boost/asio/ssl/stream.hpp:502
#11 0x0000000000da3032 in
boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t,
boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer,
boost::system::error_code const&, unsigned long>,
boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1>
(*)(), boost::arg<2> (*)()> > >::operator() (this=0x7fff8ad74f00, ec=...,
bytes_transferred=0, start=1) at /usr/include/boost/asio/impl/write.hpp:250
#12 0x0000000000d9ffbb in
boost::asio::async_write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
boost::asio::stream_socket_service<boost::asio::ip::tcp> > >,
boost::asio::mutable_buffers_1, boost::_bi::bind_t<void,
boost::_mfi::mf2<void, Peer, boost::system::error_code const&, unsigned
long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >,
boost::arg<1> (*)(), boost::arg<2> (*)()> > > (s=..., buffers=...,
handler=...) at /usr/include/boost/asio/impl/write.hpp:585
有什么想法吗?
答案 0 :(得分:4)
这是多线程问题的结果。
对于大多数Boost.Asio对象,在对象上挂起多个异步操作是安全的。它只是指定对象的并发调用是不安全的。然而,通常在某些类型上不会出现问题,例如ip::tcp::socket
。但是,ssl::stream
强调了:
应用程序还必须确保所有异步操作都在同一个隐式或显式链中执行。
在您的情况下,解决方案是wrap()
每个组合操作的完成处理程序由同一个链。这将导致在链内调用所有intermediate operations。有关线程安全性和线索细微差别的更多详细信息,请参阅this回答。
答案 1 :(得分:0)
如果您能提供代码,可能会有所帮助。很难从堆栈跟踪中分析它。如果由于某种原因你无法提供代码,那么这里有一些想法:
bio_write是一个开放的SSL方法,用于将数据写入套接字。如果您尝试直接调用此方法,可能会出现一些问题。 Someone else几个月前尝试使用它时寻求帮助,得到的答案为零。
我也在使用带有SSL的ASIO。我的代码使用一个线程将消息写入套接字,另一个线程处理从套接字读取消息。我的客户端正在与多个服务器通信,但总共有2个线程可以处理所有服务器上的所有套接字I / O.这是我写入套接字的代码,到目前为止在Windows下没有问题:
void SSLSocket::SendWorkerThread(SSLSocket* psSLS)
{
// This thread method that gets called to process the messages to be sent to the server.
//
// Since this has to be a static method, call a method on the class to handle server requests.
psSLS->ProcessSendRequests();
}
void SSLSocket::ProcessSendRequests()
{
// This method handles sending msgs to the server.
//
std::stringstream ss;
DWORD WaitResult;
Log.LogString("SSLSocket::ProcessSendRequests: Worker thread " + Logger::NumberToString(boost::this_thread::get_id()) + " started.\n", LogInfo);
// Loop until the user quits, or an error of some sort is thrown.
try
{
do
{
// If there are one or more msgs that need to be sent to a server, then send them out.
if (SendMsgQ.Count() > 0)
{
Message* pMsg = SendMsgQ.Front();
SSLSocket* pSSL = pMsg->pSSL;
SendMsgQ.Pop();
const Byte* pBuf = pMsg->pBuf;
const int BytesInMsg = pMsg->BytesInMsg;
boost::system::error_code Error;
{
Locking CodeLock(SocketLock); // Single thread the code.
// unsigned int BytesTransferred = boost::asio::write(*pSSL->pSocket, boost::asio::buffer(pBuf, BytesInMsg), Error);
boost::asio::async_write(*pSSL->pSocket, boost::asio::buffer(pBuf, BytesInMsg), boost::bind(&SSLSocket::HandleWrite, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
ss << "SSLSocket::ProcessSendRequests: # bytes sent = " << BytesInMsg << "\n";
Log.LogString(ss.str(), LogDebug2);
Log.LogBuf(pBuf, BytesInMsg, DisplayInHex, LogDebug3);
}
else
{
// Nothing to send, so go into a wait state.
WaitResult = WaitForSingleObject(hEvent, INFINITE);
if (WaitResult != 0L)
{
Log.LogString("SSLSocket::ProcessSendRequests: WaitForSingleObject event error. Code = " + Logger::NumberToString(GetLastError()) + ". \n", LogError);
}
}
} while (ReqAlive);
Log.LogString("SSLSocket::ProcessSendRequests: Worker thread " + Logger::NumberToString(boost::this_thread::get_id()) + " done.\n", LogInfo);
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::ProcessSendRequests: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
请注意,在尝试写入插座之前必须完成握手。很了解这一点。
如果这没有帮助,请尝试打印出它尝试写出的字节数。如果它试图写出大量的字节,那么可能值得研究。对于大量的ASIO可能没问题,但SSL可能没有。您也可以尝试将程序置于调试中,并在调用write语句时设置断点。尝试查看缓冲区结构以确保它是完整的以及其他对象,如io_service对象和套接字对象,以查看是否有任何踩踏或可能无意识地被破坏。
我正在使用SSL库的版本c,因为OpenSSL网站声称这是最稳定的版本。因此,如果您使用的是更新版本而其他所有版本都失败了,您可以尝试使用版本c。