Хочется придумать какую-нибудь базу для создания классов, вызовы функций в которых синхронизированы автоматом.
Что-нибудь вроде автоматического вызова EnterCriticalSection() в начале метода и LeaveCriticalSection() в конце.
Можно ли это как-нибудь сделать
красиво? Скажем, в виде базового класса, шаблона или чего-нибудь подобного?
(#define не предлагать!

)
Здравствуйте, Леший, Вы писали:
Л>Хочется придумать какую-нибудь базу для создания классов, вызовы функций в которых синхронизированы автоматом.
Л>Что-нибудь вроде автоматического вызова EnterCriticalSection() в начале метода и LeaveCriticalSection() в конце.
Л>Можно ли это как-нибудь сделать красиво? Скажем, в виде базового класса, шаблона или чего-нибудь подобного?
Л>(#define не предлагать!
)
В начале каждой такой функции создавать автоматический объект, который в своем клнструкторе будет вызывать EnterCriticalSection(), а в деструкторе — LeaveCriticalSection()
Правда код для этого (одну строчку) все равно писать надо...
Здравствуйте, Леший, Вы писали:
Л>Хочется придумать какую-нибудь базу для создания классов, вызовы функций в которых синхронизированы автоматом.
Л>Что-нибудь вроде автоматического вызова EnterCriticalSection() в начале метода и LeaveCriticalSection() в конце.
Легко.
Вот это рачитано на применение с boost::thread::mutex, но легко переделать и под нативную CRITICAL_SECTION.
////////////////////////////////////////////////////////////////////////////////////////////////
// mutex_protected.hpp
#pragma once
#include <iosfwd>
////////////////////////////////////////////////////////////////////////////////////////////////
namespace util
{
////////////////////////////////////////////////////////////////////////////////////////////////
template<class T, class mutex>
class mutex_protected
{
class locker
{
public:
locker(volatile const mutex_protected* p)
: p_(p)
, l_(*p_->m_, false)
{}
locker(const locker& other) // copy-constructable
: p_(other.p_)
, l_(*p_->m_, false)
{}
T* operator->()
{
l_.lock();
return p_->t_;
}
private:
locker& operator=(const locker&); // not assignable
volatile const mutex_protected* p_;
typename mutex::scoped_lock l_;
};
friend class locker;
public:
mutex_protected(T& t, mutex& m)
: t_(&t)
, m_(&m)
{}
public:
locker operator->() volatile const { return this; }
T* get() const { return t_; }
private:
T* t_;
mutex* m_;
};
////////////////////////////////////////////////////////////////////////////////////////////////
template<class mutex, mutex* m>
class mutex_manipulator
{
public:
mutex_manipulator()
: l_(*m)
{}
private:
typename mutex::scoped_lock l_;
};
template<class c, class t, class mutex, mutex* m>
inline std::basic_ostream<c, t>& operator<<(std::basic_ostream<c, t>& s,
const mutex_manipulator<mutex, m>&)
{
return s;
}
////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace util
////////////////////////////////////////////////////////////////////////////////////////////////
Пример использования:
extern boost::mutex clog_mutex__;
typedef util::mutex_manipulator<boost::mutex, &clog_mutex__> clog_mutex;
#define CLOG_T_MT clog_t << clog_mutex()
#define LOG_LINE_END _T("\r\n")
//
class simulator_impl : public ref_counted_impl<simulator>, private conductor_mediator
{
public:
simulator_impl()
: conductors_mt_(conductors_, mutex_conductors_)
{}
// ...
private: // conductor_mediator
void on_start(conductor* c) volatile
{
CLOG_T_MT << c << _T("Started.") << LOG_LINE_END;
}
void on_stop(conductor* c) volatile
{
// автоматом лочим на время вызова
conductors_mt_->erase(to_server_id(*c));
CLOG_T_MT << c << _T("Stopped.") << LOG_LINE_END;
}
void on_error(conductor* c, const string_t& desc) volatile
{
conductors_mt_->erase(to_server_id(*c));
CLOG_T_MT << c << _T("Failed : ") << desc << _T(".") << LOG_LINE_END;
}
private:
typedef map<server_id, conductor_p> conductors;
conductors conductors_;
boost::mutex mutex_conductors_;
volatile util::mutex_protected<conductors, boost::mutex> conductors_mt_;
Здравствуйте, Леший, Вы писали:
Л>Хочется придумать какую-нибудь базу для создания классов, вызовы функций в которых синхронизированы автоматом.
Л>Что-нибудь вроде автоматического вызова EnterCriticalSection() в начале метода и LeaveCriticalSection() в конце. :???:
Л>Можно ли это как-нибудь сделать красиво? Скажем, в виде базового класса, шаблона или чего-нибудь подобного?
Л>(#define не предлагать! ;) )
Лучше всего запроксить объект с помощью сабжа.
См., например, дискуссию
здесьАвтор: jazzer
Дата: 13.11.02
Здравствуйте, MaximE, Вы писали:
Более ясный пример:
// experiment.cpp
#include <iostream>
#include <boost/thread/detail/config.hpp>
#include <boost/thread.hpp>
#include <libs/thread/src/timeconv.inl>
#pragma comment(lib, "boost_threadd.lib")
#include "mutex_protected.hpp"
struct some
{
void say_a()
{
std::cout << "starting saying a...\n";
boost::xtime delay;
to_time(1000, delay);
boost::thread().sleep(delay);
std::cout << "end saying a.\n";
}
void say_b()
{
std::cout << "starting saying b...\n";
boost::xtime delay;
to_time(1000, delay);
boost::thread().sleep(delay);
std::cout << "end saying b.\n";
}
};
// сереализуем доступ к этому объекту
some s;
// посредством этого мьютекса
boost::mutex m;
// и этого proxy-объекта
util::mutex_protected<some, boost::mutex> thread_safe_s(s, m);
// очевидно
boost::mutex cout_mutex__;
typedef util::mutex_manipulator<boost::mutex, &cout_mutex__> cout_mutex;
void thread_1()
{
std::cout << cout_mutex() << "started thread 1.\n";
for (int n(0x10); n--;)
//s.say_a();
thread_safe_s->say_a();
std::cout << cout_mutex() << "ended thread 1.\n";
}
void thread_2()
{
std::cout << cout_mutex() << "started thread 2.\n";
for (int n(0x10); n--;)
//s.say_b();
thread_safe_s->say_b();
std::cout << cout_mutex() << "ended thread 2.\n";
}
int main()
{
boost::thread_group threads;
threads.create_thread(&thread_1);
threads.create_thread(&thread_2);
threads.join_all();
}
started thread 1.
starting saying a...
started thread 2.
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
end saying b.
starting saying a...
end saying a.
starting saying b...
ended thread 1.
end saying b.
ended thread 2.