下記のIServiceクラスに関するフィードバックをお願いします。私の知る限り、このタイプのクラスは「アクティブオブジェクト」パターンに関連しています。関連する用語を誤って使用した場合は、失礼/訂正してください。基本的に、このアクティブオブジェクトクラスを使用するクラスは、イベントループを制御するstartメソッドとstopメソッドを提供する必要があるという考え方です。このイベントループは、whileループまたはboostasioなどで実装できます。
このクラスは、イベントを新しいスレッド内または新しいスレッドで処理できるように、非ブロッキング方式で新しいスレッドを開始する役割を果たします。また、クリーンアップに関連するすべてのコードを処理する必要があります。私は最初に、サブクラスがイベントループを制御するメソッドのオーバーライドを担当するオブジェクト指向アプローチを試しましたが、クリーンアップは面倒でした。デストラクタでstopメソッドを呼び出すと、呼び出し元のクラスが手動で呼び出していない場合に、純粋仮想関数呼び出しが発生しました。停止メソッド。テンプレート化されたソリューションは、はるかにクリーンなようです。
template <typename T>
class IService : private boost::noncopyable
{
typedef boost::shared_ptr<boost::thread> thread_ptr;
public:
IService()
{
}
~IService()
{
/// try stop the service in case it's running
stop();
}
void start()
{
boost::mutex::scoped_lock lock(m_threadMutex);
if (m_pServiceThread && m_pServiceThread->joinable())
{
// already running
return;
}
m_pServiceThread = thread_ptr(new boost::thread(boost::bind(&IService::main, this)));
// need to wait for thread to start: else if destructor is called before thread has started
// Wait for condition to be signaled and then
// try timed wait since the application could deadlock if the thread never starts?
//if (m_startCondition.timed_wait(m_threadMutex, boost::posix_time::milliseconds(getServiceTimeoutMs())))
//{
//}
m_startCondition.wait(m_threadMutex);
// notify main to continue: it's blocked on the same condition var
m_startCondition.notify_one();
}
void stop()
{
// trigger the stopping of the event loop
m_serviceObject.stop();
if (m_pServiceThread)
{
if (m_pServiceThread->joinable())
{
m_pServiceThread->join();
}
// the service is stopped so we can reset the thread
m_pServiceThread.reset();
}
}
private:
/// entry point of thread
void main()
{
boost::mutex::scoped_lock lock(m_threadMutex);
// notify main thread that it can continue
m_startCondition.notify_one();
// Try Dummy wait to allow 1st thread to resume???
m_startCondition.wait(m_threadMutex);
// call template implementation of event loop
m_serviceObject.start();
}
/// Service thread
thread_ptr m_pServiceThread;
/// Thread mutex
mutable boost::mutex m_threadMutex;
/// Condition for signaling start of thread
boost::condition m_startCondition;
/// T must satisfy the implicit service interface and provide a start and a stop method
T m_serviceObject;
};
このクラスは次のように使用できます。
class TestObject3
{
public:
TestObject3()
:m_work(m_ioService),
m_timer(m_ioService, boost::posix_time::milliseconds(200))
{
m_timer.async_wait(boost::bind(&TestObject3::doWork, this, boost::asio::placeholders::error));
}
void start()
{
// simple event loop
m_ioService.run();
}
void stop()
{
// signal end of event loop
m_ioService.stop();
}
void doWork(const boost::system::error_code& e)
{
// Do some work here
if (e != boost::asio::error::operation_aborted)
{
m_timer.expires_from_now( boost::posix_time::milliseconds(200) );
m_timer.async_wait(boost::bind(&TestObject3::doWork, this, boost::asio::placeholders::error));
}
}
private:
boost::asio::io_service m_ioService;
boost::asio::io_service::work m_work;
boost::asio::deadline_timer m_timer;
};
今私の特定の質問に:
1)ブースト条件変数の使用は正しいですか?私にはちょっとしたハックのように思えます。スレッドが起動するのを待ちたかったので、条件変数を待ちました。次に、新しいスレッドがmainメソッドで起動されたら、同じ条件変数を再度待機して、最初のスレッドが続行できるようにします。次に、最初のスレッドのstartメソッドが終了すると、新しいスレッドを続行できます。これでいい?
2)OSがスレッドを正常に起動できない場合はありますか?私はこれが起こる可能性があることをどこかで読んだことを覚えています。これが可能であれば、(startメソッドでコメント化されているように)条件変数で時間指定待機を行う必要がありますか?
3)テンプレート化されたクラスがstopメソッドを「正しく」実装できなかったことを認識しています。つまり、イベントループの停止に失敗した場合、コードは結合(停止またはデストラクタのいずれか)でブロックされますが、方法がわかりません。このあたり。startメソッドとstopメソッドが正しく実装されていることを確認するのは、クラスのユーザー次第だと思いますか?
4)他の設計ミス、改善などをいただければ幸いです。
ありがとう!