commit e6e5f703ad66b49fa1f0b0ea018a9a8836a5b696
Author: David Sorber <david.sorber@gmail.com>
Date:   Sun Jul 17 16:45:07 2022 -0400

    read_test: Added SynchronizedCounter class.

diff --git a/software/read_test/src/Utilities/SynchronizedCounter.h b/software/read_test/src/Utilities/SynchronizedCounter.h
new file mode 100644
index 0000000..5dd3e90
--- /dev/null
+++ b/software/read_test/src/Utilities/SynchronizedCounter.h
@@ -0,0 +1,87 @@
+/********************************************************************
+* This software is "commercial computer software" as defined in the *
+* Federal Acquisition Regulations and is subject to BlackLynx       *
+* Inc's standard End User License Agreement.                        *
+*                                                                   *
+* CONFIDENTIAL - All source code is the propriety and confidential  *
+* information of BlackLynx Inc.                                     *
+*                                                                   *
+* Copyright 2018-2020 BlackLynx Inc.                                *
+* Unpublished -- all rights reserved under the copyright laws       *
+* of the United States.                                             *
+********************************************************************/
+#ifndef __BLNX_SYNCHRONIZEDCOUNTER_H__
+#define __BLNX_SYNCHRONIZEDCOUNTER_H__
+
+#include <chrono>
+#include <mutex>
+#include <condition_variable>
+#include <iostream>
+
+namespace BlackLynx
+{
+namespace SearchLynx
+{
+    
+template<typename T>
+class SynchronizedCounter
+{
+public:
+    
+    static_assert(std::is_integral<T>::value,
+                  "Template parameter must be an integral type");
+    
+    SynchronizedCounter()
+        : m_finalized(false),
+          m_value(0)
+    {
+    }
+
+    SynchronizedCounter(T initValue)
+        : m_finalized(false),
+          m_value(initValue)
+    {
+    }
+
+    inline void increment()
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        ++m_value;
+    }
+
+    inline void decrement()
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        --m_value;
+    }
+    
+    void finalize()
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        m_finalized = true;
+    }
+    
+    T getValue()
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        return m_value;
+    }
+    
+    T getValue(bool& finalized)
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        finalize = m_finalized
+        return m_value;
+    }
+    
+private:
+    
+    bool m_finalized;
+    T m_value;
+    std::mutex m_mutex;
+};
+
+}
+}
+
+#endif
diff --git a/software/read_test/src/Utilities/SynchronizedValue.h b/software/read_test/src/Utilities/SynchronizedValue.h
index c4143f0..9cff981 100644
--- a/software/read_test/src/Utilities/SynchronizedValue.h
+++ b/software/read_test/src/Utilities/SynchronizedValue.h
@@ -27,99 +27,100 @@ template<class T>
 class SynchronizedValue
 {
 public:
-        SynchronizedValue()
-            : m_terminateFlag(false),
-              m_flag(false)
-        {
-        }
-        
-        SynchronizedValue(T initValue)
-            : m_terminateFlag(false),
-              m_flag(false),
-              m_value(initValue)
+    
+    SynchronizedValue()
+        : m_terminateFlag(false),
+          m_flag(false)
+    {
+    }
+
+    SynchronizedValue(T initValue)
+        : m_terminateFlag(false),
+          m_flag(false),
+          m_value(initValue)
+    {
+    }
+
+    virtual ~SynchronizedValue() {}
+
+    /**
+     * Terminate any pending getValue() calls.
+     */
+    void terminate()   
+    { 
+        m_terminateFlag = true; 
+        m_CV.notify_all(); 
+    }
+
+    /**
+     * Set the value and notify any blocked getValue() calls.
+     */
+    void setValue(T value)
+    {
+        m_value = value;
         {
+            std::lock_guard<std::mutex> lock(m_mutex);
+            m_flag = true;
         }
-        
-        virtual ~SynchronizedValue() {}
-        
-        /**
-         * Terminate any pending getValue() calls.
-         */
-        void terminate()   
-        { 
-            m_terminateFlag = true; 
-            m_CV.notify_all(); 
-        }
-        
-        /**
-         * Set the value and notify any blocked getValue() calls.
-         */
-        void setValue(T value)
+        m_CV.notify_all();
+    }
+
+    /**
+     * Get the value, potentially blocking until it becomes available. Note
+     * that the "terminated" parameter should always be checked before using
+     * the returned value as a call to terminate() might cause this function
+     * to return a default initialized value.
+     * 
+     * @param terminated - indicates if a blocking wait was terminated
+     * @param block - (default: true) block while waiting for value to be set
+     * 
+     * @return the stored value
+     */
+    T getValue(bool& terminated, bool block=true)
+    {
+        terminated = false;
+
+        // If not blocking; return the current value without waiting if it
+        // hasn't yet been set
+        if (! block)
         {
-            m_value = value;
-            {
-                std::lock_guard<std::mutex> lock(m_mutex);
-                m_flag = true;
-            }
-            m_CV.notify_all();
+            std::lock_guard<std::mutex> lock(m_mutex);
+            return m_value;
         }
-        
-        /**
-         * Get the value, potentially blocking until it becomes available. Note
-         * that the "terminated" parameter should always be checked before using
-         * the returned value as a call to terminate() might cause this function
-         * to return a default initialized value.
-         * 
-         * @param terminated - indicates if a blocking wait was terminated
-         * @param block - (default: true) block while waiting for value to be set
-         * 
-         * @return the stored value
-         */
-        T getValue(bool& terminated, bool block=true)
+
+        std::unique_lock<std::mutex> muxLock(m_mutex);
+        while (m_flag == false)
         {
-            terminated = false;
-            
-            // If not blocking; return the current value without waiting if it
-            // hasn't yet been set
-            if (! block)
-            {
-                std::lock_guard<std::mutex> lock(m_mutex);
-                return m_value;
-            }
-            
-            std::unique_lock<std::mutex> muxLock(m_mutex);
-            while (m_flag == false)
+            m_CV.wait_for(muxLock, std::chrono::milliseconds(1));
+
+            // If we've been asked to terminate, break out of the loop and abort
+            if (m_terminateFlag)
             {
-                m_CV.wait_for(muxLock, std::chrono::milliseconds(1));
-
-                // If we've been asked to terminate, break out of the loop and abort
-                if (m_terminateFlag)
-                {
-                    terminated = true;
-                    break;
-                }
+                terminated = true;
+                break;
             }
-            muxLock.unlock();
-            
-            return m_value;
-        }
-        
-        /**
-         * Reset the internal flag to allow the value to be set again. Note this
-         * function must be used with care! 
-         */
-        void reset()
-        {
-            std::lock_guard<std::mutex> lock(m_mutex);
-            m_flag = false;
-        }
-        
-        void reset(T newVal)
-        {
-            std::lock_guard<std::mutex> lock(m_mutex);
-            m_flag = false;
-            m_value = newVal;
         }
+        muxLock.unlock();
+
+        return m_value;
+    }
+
+    /**
+     * Reset the internal flag to allow the value to be set again. Note this
+     * function must be used with care! 
+     */
+    void reset()
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        m_flag = false;
+    }
+
+    void reset(T newVal)
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        m_flag = false;
+        m_value = newVal;
+    }
 
 private:
     
