これは私のアプリケーションで問題が再現する比較的単純なプログラムです:私はLinuxマシン上でそれを実行すると不適切なスレッドコンテキストでshared_ptrが破壊されないようにするにはどうすればよいですか?
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/noncopyable.hpp>
#include <boost/thread.hpp>
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
class worker : boost::noncopyable {
public:
explicit worker(boost::asio::io_service& io);
~worker();
void just_do_it(const std::function<void()>& when_done);
private:
boost::asio::io_service& io_;
boost::asio::io_service worker_io_;
boost::thread thread_;
};
worker::worker(boost::asio::io_service& io)
: io_(io)
{
thread_ = boost::thread([this] {
boost::asio::io_service::work my_work(worker_io_);
worker_io_.run();
});
}
worker::~worker()
{
worker_io_.stop();
std::clog << "join...\n";
thread_.join();
}
void worker::just_do_it(const std::function<void()>& when_done)
{
worker_io_.post([this, when_done] {
io_.post(when_done);
boost::asio::steady_timer(worker_io_, std::chrono::seconds(1)).wait();
});
}
int main()
{
boost::asio::io_service io;
boost::asio::steady_timer timer(io, std::chrono::seconds(5));
timer.async_wait(std::bind([] { std::clog << "terminating...\n"; }));
{
auto my_worker = std::make_shared<worker>(io);
my_worker->just_do_it([my_worker] {
std::clog << "did it\n";
my_worker->just_do_it([my_worker] {
std::clog << "did it second time\n";
// now my_worker is not needed and we allow it to die
});
});
}
io.run();
}
を私が参照してください。
それが原因のshared_ptrのクラッシュdid it
did it second time
join...
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::thread_resource_error> >'
what(): boost thread: trying joining itself: Resource deadlock avoided
Aborted
はworker`に労働者のデストラクタを呼び出しますのスレッド。私はこのように修正することができます:
std::shared_ptr<worker> holder;
{
holder = std::make_shared<worker>(io);
holder->just_do_it([&holder] {
std::clog << "did it\n";
holder->just_do_it([&holder] {
std::clog << "did it second time\n";
// now worker is not needed and we destroy it
holder.reset();
});
});
}
しかし、これは手動でのオブジェクトの寿命管理です。それは新しいものを使用して削除するよりもあまり良くありません。それを避ける方法はありますか?
とにかく後でスレッドに参加したいですか?だから、あなたはそれの外側のスレッドへのハンドルが必要です。 –
スレッドはワーカークラスメンバ変数を使用できるので、ワーカーを破壊する前にスレッドを停止する必要があります。 –
あなたの解決策は問題のあるコードよりも自動ではありませんが、ポインタが破棄されたときに変更するだけです(例外的に手動の 'new' /' delete'よりも優れています)。あなたは別の解決策を考えることができますが、あなたが提供するものは最も簡単なIMOのようです。 – piwi