thread safe session class added using boost::mutex
authorMarc Cromme <marc@indexdata.dk>
Thu, 6 Oct 2005 21:41:12 +0000 (21:41 +0000)
committerMarc Cromme <marc@indexdata.dk>
Thu, 6 Oct 2005 21:41:12 +0000 (21:41 +0000)
boost thread test added
build environment broken, needs to be fixed

Doxyfile.in
configure.in
src/Makefile.am
src/design.h
src/design_main.cpp
src/test_boost_threads.cpp [new file with mode: 0644]
src/test_filter1.cpp
src/test_filter2.cpp
src/test_session1.cpp [new file with mode: 0644]

index bf2ec89..491ea8e 100644 (file)
@@ -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.
index d58baad..856f384 100644 (file)
@@ -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
index 16b46d3..d059692 100644 (file)
@@ -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
index 10e06a6..a2b08b9 100644 (file)
@@ -5,6 +5,8 @@
 #include <stdexcept>
 #include <list>
 
+#include <boost/thread/mutex.hpp>
+
 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 Filter *>::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<const Filter *> 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 Filter *>::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<const Filter *> 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;
+      
+    };
+
+
   
 }
 
index f0b571e..c65fc9c 100644 (file)
@@ -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 (file)
index 0000000..8a26cab
--- /dev/null
@@ -0,0 +1,60 @@
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+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
+ */
index 488da1f..1fa0d54 100644 (file)
@@ -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";
index f7db7fe..e5aa309 100644 (file)
@@ -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 (file)
index 0000000..0c0abc3
--- /dev/null
@@ -0,0 +1,38 @@
+
+#include <iostream>
+#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
+ */