C++ > ライブラリ > mt_stream


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

概要

マルチスレッドでも出力の順番を保証する ostream ラッパークラス。
ロック用にBoostを使ってるので要Boost。
Boost使わずにロックできるならBoostなしでも可。

使い方

util::mt_ostream mt(std::cout);
 
void multithreded_func()
{
	mt << "foo" << "bar" << std::endl; // 出力が"foobar"になることを保証
}

コード

#ifndef UTIL_MT_STREAM_H
#define UTIL_MT_STREAM_H
 
#include <iostream>
 
#include <boost/thread.hpp>
 
namespace util {
 
namespace detail {
 
/* Boost を使用したロック用クラス */
class boost_lock {
public:
	boost_lock()
	{}
	~boost_lock()
	{}
	void lock()
	{
		mutex_.lock();
	}
	void unlock()
	{
		mutex_.unlock();
	}
private:
	explicit boost_lock(const boost_lock&);
	boost_lock &operator=(const boost_lock&);
	boost::mutex mutex_;
};
 
/* 例外安全ロッククラス */
template<class Lk>
class lock_holder {
public:
	lock_holder(Lk &lock)
		: lock_(lock)
	{
		lock_.lock();
	}
	~lock_holder()
	{
		try {
			lock_.unlock();
		} catch(...) {}
	}
private:
	explicit lock_holder(const lock_holder&);
	lock_holder &operator=(const lock_holder&);
 
	Lk &lock_;
};
 
/* Boostを使用したスレッド・ローカル・ストレージクラス */
template<class Ch>
class boost_thread_specific_storage {
public:
	boost_thread_specific_storage(size_t num)
		: default_size_(num)
	{}
 
	~boost_thread_specific_storage()
	{}
 
	Ch *begin()
	{
		return &(get_storage()[0]);
	}
 
	void resize(size_t new_size)
	{
		get_storage().resize(new_size);
	}
 
	size_t size()
	{
		return get_storage().size();
	}
 
	void push_back(Ch c)
	{
		get_storage().push_back(c);
	}
 
	void clear()
	{
		get_storage().clear();
	}
 
private:
	std::vector<Ch> &get_storage()
	{
		std::vector<Ch> *p = storage_.get();
		if(p==NULL) {
			p = new std::vector<Ch>;
			p->reserve(default_size_);
			storage_.reset(p);
		}
		return *p;
	}
 
	size_t default_size_;
	boost::thread_specific_ptr<std::vector<Ch> > storage_;
};
 
/* スレッドセーフなstreambufクラス */
template <class Ch, class Lk, class St, class Tr=std::char_traits<Ch> >
class basic_mt_streambuf : public std::basic_streambuf<Ch,Tr> {
public:
	typedef typename std::basic_streambuf<Ch, Tr>::int_type int_type;
 
	basic_mt_streambuf(std::basic_ostream<Ch,Tr>& os)
		: out_(os), buf_(16)
	{}
 
	~basic_mt_streambuf()
	{}
 
protected:
 
	int_type overflow(int_type c=Tr::eof())
	{
		if(c!=Tr::eof()) {
			buf_.push_back(c);
			return Tr::not_eof(c);
		}
		return Tr::eof();
	}
 
	int sync()
	{
		lock_holder<Lk> l(lock_);
		out_.write(buf_.begin(), buf_.size());
		out_.flush();
		buf_.clear();
		return 0;
	}
 
private:
	explicit basic_mt_streambuf(const basic_mt_streambuf&);
	basic_mt_streambuf &operator=(const basic_mt_streambuf&);
 
    std::basic_ostream<Ch,Tr> &out_;
	St buf_;
	Lk lock_;
};
 
/**
 ostreamのラッパークラス
 @param Ch 文字型(charまたはwchar_t)
 @param Lk 使用するロック用クラス
 @param St 使用するスレッド・ローカル・ストレージクラス
 @param Tr traitsクラス
 */
template <class Ch, class Lk, class St, class Tr=std::char_traits<Ch> >
class basic_mt_ostream : public std::basic_iostream<Ch,Tr> {
public:
	basic_mt_ostream(std::basic_ostream<Ch,Tr> &os) 
		: std::basic_iostream<Ch,Tr>(&streambuf_), streambuf_(os)
	{}
	~basic_mt_ostream()
	{}
 
private:
	explicit basic_mt_ostream(const basic_mt_ostream&);
	basic_mt_ostream &operator=(const basic_mt_ostream&);
 
	basic_mt_streambuf<Ch, Lk, St, Tr> streambuf_;
};
 
}
 
typedef detail::basic_mt_ostream<char, detail::boost_lock, detail::boost_thread_specific_storage<char> > mt_ostream;
typedef detail::basic_mt_ostream<wchar_t, detail::boost_lock, detail::boost_thread_specific_storage<wchar_t> > mt_wostream;
 
}
 
#endif
|新しいページ|検索|ページ一覧|RSS|@ウィキご利用ガイド | 管理者にお問合せ
|ログイン|