さまざまなブースト機能を使用して、イベント駆動型のアプリケーションを開発しています。私はマルチスレッド アーキテクチャを ASIO の io_service オブジェクトに基づいて構築することを計画しています。これにより、作業の各アトムは、それぞれが を呼び出した 1 つ以上のスレッドのスレッド グループによってディスパッチされrun()
ます。
このエンジンの以前の「概念実証」バージョンでは、1 つのio_service
オブジェクトを使用して、デッドライン タイマー、ネットワーク I/O、ポストされた操作など、さまざまなタスクをディスパッチしていました。これらの初期のレンディションがそうであるように、この以前のバージョンでは、一度にディスパッチする予定のイベントがいくつかしかありませんでした。自分が正しい方向に進んでいると確信したので、エンジンの一部をリファクタリングして、より細かい粒度と拡張性の向上をサポートしました。しかし、この新しいバージョンは、オブジェクト内の不適切なポインタと思われるものでクラッシュしていio_service
ます。
私が経験している問題に対して、単純化された再現可能なテスト ケースを作成しようと思います。しかし、その前に、私のアーキテクチャが基づいている前提を確認したいと思います…</p>
単一のオブジェクトは、多数のネットワーク オブジェクト (tcp および udp 解決、ソケット、タイマー、およびオブジェクト参照io_service
を取るその他のビースト) 間で共有できます。io_service
私が尋ねる理由は、ドキュメントやオンライン ディスカッションで明確に述べられていることを見つけることができなかったからです。私の io_service に何か問題があることを示すもう 1 つのヒントは、tcp::socket への呼び出しの下流のどこかで発生しているクラッシュがasync_connect()
、有効なエンドポイントとハンドラーを使用していることです。async_connect()
呼び出しの実装の最後の行this->get_service()
。stream_socket_serviceget_service()
が返すはずのポインターは、最終的に 0x2 になります。これは、ENIAC 以来、優れたポインター値ではありませんでした。
私の環境…</p>
Boost バージョン 48 から 52 でこの問題のデバッグを試みました。
私は OSX で開発を行っており、4.2 から 4.7.3 までのさまざまな gcc 4.x コンパイラ バージョンを試しました。
この破損の問題が発生する前にセッションで行った非同期操作には、いくつかのタイマー、udp 解決、および tcp 解決が含まれます。
私が行っているソケットは
async_connect()
、呼び出しの直前にヒープに割り当てられ、コンストラクターで io_service が渡されました。私は
io_service::work
オブジェクトを持っています。私は(まだ)ストランドを使用していません。
これは誰かが助けるのに十分な情報ですか、それともコンパイル可能なコードを提出する必要がありますか? また、他の SO 読者と同様に、サービスとは何かについての入門書もio_service
大好きです。
更新 #1: これは、私が経験している問題の最小限の特徴であり、まだクラッシュすることを確認しています。最新のosx MLでBoost 1.52.0、gcc 4.6.3を使用して構築しました。
#include <stdlib.h>
#include <string>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/asio.hpp>
namespace foo {
namespace asio = boost::asio;
class ios_threads : private boost::noncopyable
{
public:
ios_threads(bool strt = false)
: work_(new asio::io_service::work(ios_))
{
if (strt)
start();
}
static asio::io_service &ios()
{
return ios_;
}
void start()
{
threads_.create_thread(boost::bind(&ios_threads::run, this));
}
void wait()
{
threads_.join_all();
}
private:
void run()
{
while (true) {
try {
ios_.run();
}
catch (std::exception &e) {
delete work_;
break;
}
}
printf("Shutting down.\n");
}
static asio::io_service ios_;
asio::io_service::work *work_;
boost::thread_group threads_;
};
asio::io_service ios_threads::ios_;
struct op;
typedef op * opPtr;
struct op
{
typedef boost::recursive_mutex mutex_type;
op(op *del)
: delegate_(del)
{
}
virtual ~op()
{
}
bool start_async()
{
boost::unique_lock< mutex_type > lock(mutex_);
return start_it();
}
protected:
virtual bool start_it()
{
return false;
}
virtual void did_it(const boost::system::error_code& error)
{
}
void completion_handler(const boost::system::error_code& error)
{
boost::unique_lock< mutex_type > lock(mutex_);
did_it(error);
}
opPtr delegate_;
mutable mutex_type mutex_;
};
struct interface_search : public op
{
typedef op super;
interface_search(op *del)
: super(del),
udp_resolver_(ios_threads::ios())
{
it_ = NULL;
}
bool start_it()
{
try {
std::string hostname = boost::asio::ip::host_name();
asio::ip::udp::resolver::query query(hostname, "", asio::ip::resolver_query_base::numeric_service | boost::asio::ip::resolver_query_base::passive);
udp_resolver_.async_resolve(query, boost::bind(&interface_search::udp_handler, this, asio::placeholders::error, asio::placeholders::iterator));
}
catch (std::exception& e) {
printf("UDP resolve operation failed. Exception: %s", e.what());
}
return super::start_it();
}
protected:
void udp_handler(const boost::system::error_code& error, asio::ip::udp::resolver::iterator it)
{
it_ = ⁢
completion_handler(error);
}
void did_it(const boost::system::error_code& error)
{
if (error == asio::error::operation_aborted)
return;
op *del = delegate_;
if (del)
del->start_async();
}
asio::ip::udp::resolver udp_resolver_;
asio::ip::udp::resolver::iterator *it_;
};
struct google_connect : public op
{
typedef op super;
google_connect()
: super(NULL),
socket_(ios_threads::ios())
{
}
void endpoint(asio::ip::tcp::endpoint &endpoint)
{
endpoint_ = endpoint;
}
bool start_it()
{
try {
// Crashes in the following call!
socket_.async_connect(endpoint_, boost::bind(&google_connect::connect_handler, this, asio::placeholders::error));
}
catch (std::exception& e) {
printf(e.what());
}
return super::start_it();
}
void connect_handler(const boost::system::error_code& error)
{
completion_handler(error);
}
void did_it(const boost::system::error_code& error)
{
if (error == asio::error::operation_aborted)
return;
boost::asio::ip::address addr = socket_.local_endpoint().address();
printf(addr.to_string().c_str());
}
asio::ip::tcp::socket socket_;
asio::ip::tcp::endpoint endpoint_;
};
struct google_resolve : public op
{
typedef op super;
google_resolve()
: super(new google_connect()),
resolver_(ios_threads::ios())
{
it_ = NULL;
}
bool start_it()
{
try {
asio::ip::tcp::resolver::query query(asio::ip::tcp::v4(), "google.com", "http");
resolver_.async_resolve(query, boost::bind(&google_resolve::tcp_handler, this, asio::placeholders::error, asio::placeholders::iterator));
}
catch (std::exception& e) {
printf(e.what());
}
return super::start_it();
}
protected:
void tcp_handler(const boost::system::error_code& error, asio::ip::tcp::resolver::iterator it)
{
it_ = ⁢
completion_handler(error);
}
void did_it(const boost::system::error_code& error)
{
if (error == asio::error::operation_aborted)
return;
asio::ip::tcp::resolver::iterator last;
if (*it_ != last) {
google_connect *gc = static_cast< google_connect * >(delegate_);
if (gc) {
asio::ip::tcp::endpoint ep = **it_;
gc->endpoint(ep);
gc->start_async();
super::did_it(error);
}
}
}
asio::ip::tcp::resolver resolver_;
asio::ip::tcp::resolver::iterator *it_;
};
} // namespace foo
int main(int argc, const char * argv[])
{
try {
foo::ios_threads threads(false);
foo::opPtr ops_;
ops_ = new foo::interface_search(
new foo::google_resolve()
);
ops_->start_async();
threads.start();
threads.wait();
}
catch (std::exception& e) {
printf(e.what());
}
return 0;
}