大量のデータをファイル出力するときに、バックグランドでファイル書き出しをしてほしいなということで、そんなクラスを作ってみた。
仕様は次の通り。
- ファイル名を渡してインスタンスを生成する。
- ライト関数に文字列を渡すと、キューに登録する。
- インスタンスは別スレッドで動作し、キューに文字列が入ったらファイルに書き出す。
- TERMINATEコマンドを送ると、キューに残っているものをすべて書き出し、終了する。
- SUSPENDコマンドを送ると、書き出し処理を中断する。
- RESUMEコマンドを送ると、書き出し処理を再開する。
クラスの定義は次の通り。
- class DBGWriter{
- private:
- boost::thread th_; //ライタ関数が動作するスレッド
- std::queue<std::string> strQueue_; //書き出し文字列のキュー
- boost::mutex mutex_;
- boost::condition_variable_any condition_;
- std::string outputFileName_; //出力ファイル名
- std::ofstream ofStream_; //ファイル出力ストリーム
- bool isWritable_; //書き込み可のフラグ
- bool isSuspend_; //サスペンドのフラグ
- DBGWriter(){};
- void writer(); //ライタ関数
- public:
- DBGWriter(std::string outputFileName);
- void write(std::string str); //書き出し文字列登録関数
- void sendCmd(DBGW_CMD cmd); //コマンド送信関数
- };
ライタ関数は次のようになっている。
- void DBGWriter::writer()
- {
- boost::mutex::scoped_lock lock(this->mutex_);
- while(this->isWritable_){
- while(this->isSuspend_){
- this->condition_.wait(lock);
- }
- while(this->strQueue_.empty()){
- this->condition_.wait(lock);
- }
- this->ofStream_ << this->strQueue_.front() << std::flush;
- this->strQueue_.pop();
- }
- while(!this->strQueue_.empty()){
- this->ofStream_ << this->strQueue_.front() << std::flush;
- this->strQueue_.pop();
- }
- }
5〜14行目が通常の書き込み可能状態の処理となっている。6〜8行目、9〜11行目でそれぞれサスペンド時とキューが空の時の待ち状態に入る。キューに文字列が入ったら、12行目でファイルに出力し、13行目でキューから取り除いている。15〜19行目はTERMINATEコマンド発行時の処理となっている。キューが空になるまで、キューの中身をファイルに書き出している。
RESUMEコマンドが発行されるか、キューに文字列が入れられると、boost::condition_variable_any::notify_all()が発行され、待ち状態を解除するようになっている。
他はたいしたことないので、割愛する。
全体のソースはこちら→ bgw.tar.gzをダウンロード