From: Marc Cromme Date: Thu, 6 Oct 2005 21:41:12 +0000 (+0000) Subject: thread safe session class added using boost::mutex X-Git-Tag: YP2.0.0.2~255 X-Git-Url: http://lists.indexdata.dk/?a=commitdiff_plain;h=c90fa1d9d80ba80198953b34c2e5a3134d1b5402;p=metaproxy-moved-to-github.git thread safe session class added using boost::mutex boost thread test added build environment broken, needs to be fixed --- diff --git a/Doxyfile.in b/Doxyfile.in index bf2ec89..491ea8e 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -17,7 +17,7 @@ # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. -PROJECT_NAME = YP2 +PROJECT_NAME = @PACKAGE@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or @@ -94,10 +94,11 @@ ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited -# members of a class in the documentation of that class as if those members were -# ordinary class members. Constructors, destructors and assignment operators of -# the base classes will not be shown. +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show +# all inherited members of a class in the documentation of that class +# as if those members were ordinary class members. Constructors, +# destructors and assignment operators of the base classes will not be +# shown. INLINE_INHERITED_MEMB = NO @@ -1053,12 +1054,12 @@ COLLABORATION_GRAPH = YES # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. -UML_LOOK = NO +UML_LOOK = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. -TEMPLATE_RELATIONS = NO +TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented @@ -1080,7 +1081,7 @@ INCLUDED_BY_GRAPH = YES # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. -CALL_GRAPH = NO +CALL_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. diff --git a/configure.in b/configure.in index d58baad..856f384 100644 --- a/configure.in +++ b/configure.in @@ -15,7 +15,7 @@ YAZ_DOC USEMARCON_INIT AC_CHECK_FUNCS(setrlimit getrlimit gettimeofday) -AC_CHECK_HEADERS(pwd.h sys/resource.h sys/stat.h sys/time.h sys/types.h sys/wait.h unistd.h) +AC_CHECK_HEADERS(pwd.h sys/resource.h sys/stat.h sys/time.h sys/types.h sys/wait.h unistd.h boost/thread/mutex.hpp) AC_CHECK_LIB(dl,dlopen) dnl dnl ----- libXSLT diff --git a/src/Makefile.am b/src/Makefile.am index 16b46d3..d059692 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,10 @@ -## $Id: Makefile.am,v 1.4 2005-10-06 19:33:58 adam Exp $ +## $Id: Makefile.am,v 1.5 2005-10-06 21:41:12 marc Exp $ AM_CXXFLAGS = $(YAZPPINC) $(XSLT_CFLAGS) $(USEMARCONINC) bin_PROGRAMS = -check_PROGRAMS = test_filter1 test_filter2 test_thread_pool_observer +check_PROGRAMS = test_filter1 test_filter2 test_session1 \ + test_thread_pool_observer test_boost_threads noinst_PROGRAMS = p2 design TESTS=$(check_PROGRAMS) @@ -12,6 +13,10 @@ design_SOURCES=design.h design_main.cpp test_filter1_SOURCES=test_filter1.cpp test_filter2_SOURCES=test_filter2.cpp +test_session1_SOURCES=test_session1.cpp +test_boost_threads_SOURCES=test_boost_threads.cpp +test_thread_pool_observer_SOURCES = test_thread_pool_observer.cpp \ + thread_pool_observer.cpp thread_pool_observer.h p2_SOURCES=p2_frontend.cpp p2_msg.cpp p2.cpp p2_frontend.h \ p2_config.cpp p2_config.h \ @@ -20,10 +25,8 @@ p2_SOURCES=p2_frontend.cpp p2_msg.cpp p2.cpp p2_frontend.h \ p2_xmlerror.cpp p2_xmlerror.h \ thread_pool_observer.cpp thread_pool_observer.h -test_thread_pool_observer_SOURCES = test_thread_pool_observer.cpp \ - thread_pool_observer.cpp thread_pool_observer.h -LDADD= $(YAZPPLALIB) $(XSLT_LIBS) $(USEMARCONLALIB) +LDADD= $(YAZPPLALIB) $(XSLT_LIBS) $(USEMARCONLALIB) -lboost_thread # Modules diff --git a/src/design.h b/src/design.h index 10e06a6..a2b08b9 100644 --- a/src/design.h +++ b/src/design.h @@ -5,6 +5,8 @@ #include #include +#include + namespace yp2 { class Package; @@ -12,26 +14,24 @@ namespace yp2 { class Filter { public: virtual ~Filter(){}; + + ///sends Package off to next Filter, returns altered Package virtual Package & process(Package & package) const { return package; }; virtual void configure(){}; - - // set/get the C++ way .. just as showoff - - // get function - returns copy and keeps object const, - // thus is right val in assignment + + /// get function - right val in assignment std::string name() const { return m_name; } - // set function - returns reference and changes object, - // thus is left val in assignment + + /// set function - left val in assignment std::string & name() { return m_name; } - // more traditional set function, taking const reference - // or copy (here const ref for demo), returning ref to object - // can be chained with other similar functions! + + /// set function - can be chained Filter & name(const std::string & name){ m_name = name; return *this; @@ -42,61 +42,104 @@ namespace yp2 { }; - class Filter_Exception : public std::runtime_error { + class FilterException : public std::runtime_error { public: - Filter_Exception(const std::string message) - : std::runtime_error("Filter_Exception: " + message){ + FilterException(const std::string message) + : std::runtime_error("FilterException: " + message){ }; }; + + class RouterException : public std::runtime_error { + public: + RouterException(const std::string message) + : std::runtime_error("RouterException: " + message){}; + }; + + + class Router { + public: + Router(){}; + virtual ~Router(){}; - class Router { - public: - Router(){}; - virtual ~Router(){}; - virtual const Filter * - move(const Filter *filter, const Package *package) const { - std::list::const_iterator it; - it = m_filter_list.begin(); - if (filter) - { - for (; it != m_filter_list.end(); it++) - if (*it == filter) - { - it++; - break; - } - } - if (it == m_filter_list.end()) - { - //throw Router_Exception("no routing rules known"); - return 0; - } - return *it; - }; - virtual void configure(){}; - Router & rule(const Filter &filter){ - m_filter_list.push_back(&filter); - return *this; - } - private: - Router(const Router &); - Router& operator=(const Router &); - std::list m_filter_list; - }; + /// determines next Filter to use from current Filter and Package + virtual const Filter *move(const Filter *filter, + const Package *package) const { + return 0; + }; + + /// re-read configuration of routing tables + virtual void configure(){}; + + /// add routing rule expressed as Filter to Router + virtual Router & rule(const Filter &filter){ + return *this; + } + private: + /// disabled because class is singleton + Router(const Router &); + + /// disabled because class is singleton + Router& operator=(const Router &); + }; + + class RouterChain : public Router { + public: + RouterChain(){}; + virtual ~RouterChain(){}; + virtual const Filter *move(const Filter *filter, + const Package *package) const { + std::list::const_iterator it; + it = m_filter_list.begin(); + if (filter) + { + for (; it != m_filter_list.end(); it++) + if (*it == filter) + { + it++; + break; + } + } + if (it == m_filter_list.end()) + { + //throw RouterException("no routing rules known"); + return 0; + } + return *it; + }; + virtual void configure(){}; + RouterChain & rule(const Filter &filter){ + m_filter_list.push_back(&filter); + return *this; + } + protected: + std::list m_filter_list; + private: + /// disabled because class is singleton + RouterChain(const RouterChain &); + + /// disabled because class is singleton + RouterChain& operator=(const RouterChain &); + }; - class Router_Exception : public std::runtime_error { + + class PackageException : public std::runtime_error { public: - Router_Exception(const std::string message) - : std::runtime_error("Router_Exception: " + message){}; + PackageException(const std::string message) + : std::runtime_error("PackageException: " + message){ + }; }; class Package { public: - // send package to it's next filter defined in chain + Package(unsigned long int id = 0, bool close = 0) + : m_session_id(id), m_session_close(close), + m_filter(0), m_router(0), m_data(0) {} + + /// send Package to it's next Filter defined in Router Package & move() { m_filter = m_router->move(m_filter, this); if (m_filter) @@ -105,62 +148,83 @@ namespace yp2 { return *this; } - // get function - returns copy and keeps object const, - // thus is right val in assignment + + /// get function - right val in assignment + unsigned int session_id() const { + return m_session_id; + } + + /// get function - right val in assignment + unsigned int session_close() const { + return m_session_close; + } + + + /// get function - right val in assignment unsigned int data() const { return m_data; } - // set function - returns reference and changes object, - // thus is left val in assignment + + /// set function - left val in assignment unsigned int & data() { return m_data; } - - // more traditional set function, taking const reference - // or copy (here const ref for demo), returning ref to object - // can be chained with other similar functions! + + /// set function - can be chained Package & data(const unsigned int & data){ m_data = data; return *this; } - // get function - returns copy and keeps object const, - // thus is right val in assignment + //Router router() const { // return m_router; //} - // set function - returns reference and changes object, - // thus is left val in assignment + //Router & router() { // return m_router; //} - // more traditional set function, taking const reference - // or copy (here const ref for demo), returning ref to object - // can be chained with other similar functions! + + /// set function - can be chained Package & router(const Router &router){ m_filter = 0; m_router = &router; return *this; } - Package() { - m_filter = 0; - m_router = 0; - m_data = 0; - } + private: - unsigned int m_data; + unsigned long int m_session_id; + bool m_session_close; const Filter *m_filter; const Router *m_router; + unsigned int m_data; }; - - class Package_Exception : public std::runtime_error { - public: - Package_Exception(const std::string message) - : std::runtime_error("Package_Exception: " + message){ + + class Session + { + public: + Session() : m_id(0){}; + /// returns next id, global state of id protected by boost::mutex + long unsigned int id() { + boost::mutex::scoped_lock scoped_lock(m_mutex); + ++m_id; + return m_id; }; - }; + private: + /// disabled because class is singleton + Session(const Session &); + + /// disabled because class is singleton + Session& operator=(const Session &); + + boost::mutex m_mutex; + unsigned long int m_id; + + }; + + } diff --git a/src/design_main.cpp b/src/design_main.cpp index f0b571e..c65fc9c 100644 --- a/src/design_main.cpp +++ b/src/design_main.cpp @@ -15,7 +15,7 @@ int main(int argc, char **argv) { filter.name() = "filter1 rename"; std::cout << "filter: " << filter.name() << "\n"; - throw yp2::Filter_Exception("finished"); + throw yp2::FilterException("finished"); } catch (std::exception &e) { std::cout << e.what() << "\n"; @@ -54,7 +54,7 @@ int main(int argc, char **argv) { pack_in.move(); std::cout << "pack_in.move()" << "\n"; - throw yp2::Router_Exception("finished"); + throw yp2::RouterException("finished"); } catch (std::exception &e) { diff --git a/src/test_boost_threads.cpp b/src/test_boost_threads.cpp new file mode 100644 index 0000000..8a26cab --- /dev/null +++ b/src/test_boost_threads.cpp @@ -0,0 +1,60 @@ + +#include +#include +#include + +boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe! + +class counter +{ + public: + counter() : count(0) { } + + int increment() { + boost::mutex::scoped_lock scoped_lock(mutex); + return ++count; + } + + private: + boost::mutex mutex; + int count; +}; + +counter c; + +void change_count() +{ + int i = c.increment(); + boost::mutex::scoped_lock scoped_lock(io_mutex); + std::cout << "count == " << i << std::endl; +} + + + +int main(int, char*[]) +{ + try + { + const int num_threads = 4; + boost::thread_group thrds; + for (int i=0; i < num_threads; ++i) + thrds.create_thread(&change_count); + + thrds.join_all(); + + } + catch (std::exception &e) + { + std::cout << e.what() << "\n"; + exit(1); + } + exit(0); +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/test_filter1.cpp b/src/test_filter1.cpp index 488da1f..1fa0d54 100644 --- a/src/test_filter1.cpp +++ b/src/test_filter1.cpp @@ -16,13 +16,16 @@ int main(int argc, char **argv) TFilter filter; filter.name("filter1"); + std::cout << filter.name() << std::endl; if (filter.name() != "filter1") { std::cout << "filter name does not match 1\n"; exit(1); } + filter.name() = "filter1 rename"; + std::cout << filter.name() << std::endl; if (filter.name() != "filter1 rename") { std::cout << "filter name does not match 2\n"; diff --git a/src/test_filter2.cpp b/src/test_filter2.cpp index f7db7fe..e5aa309 100644 --- a/src/test_filter2.cpp +++ b/src/test_filter2.cpp @@ -5,6 +5,7 @@ class FilterConstant: public yp2::Filter { public: yp2::Package & process(yp2::Package & package) const { + std::cout << name() + ".process()" << std::endl; package.data() = 1234; return package.move(); }; @@ -14,6 +15,7 @@ public: class FilterDouble: public yp2::Filter { public: yp2::Package & process(yp2::Package & package) const { + std::cout << name() + ".process()" << std::endl; package.data() = package.data() * 2; return package.move(); }; @@ -24,10 +26,12 @@ int main(int argc, char **argv) { try { FilterConstant fc; + fc.name() = "FilterConstant"; FilterDouble fd; + fd.name() = "FilterDouble"; { - yp2::Router router1; + yp2::RouterChain router1; // test filter set/get/exception router1.rule(fc); @@ -46,7 +50,7 @@ int main(int argc, char **argv) } } { - yp2::Router router1; + yp2::RouterChain router1; router1.rule(fd); router1.rule(fc); diff --git a/src/test_session1.cpp b/src/test_session1.cpp new file mode 100644 index 0000000..0c0abc3 --- /dev/null +++ b/src/test_session1.cpp @@ -0,0 +1,38 @@ + +#include +#include "design.h" + +int main(int argc, char **argv) +{ + // test session + try { + yp2::Session session; + unsigned long int id; + id = session.id(); + std::cout << "Session.id() == " << id << std::endl; + id = session.id(); + std::cout << "Session.id() == " << id << std::endl; + id = session.id(); + std::cout << "Session.id() == " << id << std::endl; + + if (id != 3) + { + std::cout << "Fail: Session.id() != 3\n"; + exit(1); + } + } + + catch (std::exception &e) { + std::cout << e.what() << "\n"; + exit(1); + } + exit(0); +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */