commit fea928c10d668e57a577fdb06fa18463702e373d
Author: David Sorber <david.sorber@gmail.com>
Date:   Mon Jul 16 20:19:25 2018 -0400

    Adding ProtectedAndSynchronizedQueue.

diff --git a/software/photo_compress_archiver/ProtectedAndSynchronizedQueue.h b/software/photo_compress_archiver/ProtectedAndSynchronizedQueue.h
new file mode 100644
index 0000000..282ebe5
--- /dev/null
+++ b/software/photo_compress_archiver/ProtectedAndSynchronizedQueue.h
@@ -0,0 +1,132 @@
+#ifndef __PROTECTEDANDSYNCHRONIZEDQUEUE_H__
+#define __PROTECTEDANDSYNCHRONIZEDQUEUE_H__
+
+#include <queue>
+#include <mutex>
+#include <condition_variable>
+#include <iostream>
+
+    
+template<class T>
+class ProtectedAndSynchronizedQueue
+{
+public:
+        ProtectedAndSynchronizedQueue()
+        {
+            m_terminateFlag = false;
+        }
+        
+        virtual ~ProtectedAndSynchronizedQueue() {};
+        
+        /*
+         * add a new element to the back of the queue
+         */
+        void push_back(T newElement)
+        {
+            {
+                std::lock_guard<std::mutex> lock(m_mutex);
+                m_queue.push(newElement);
+            }
+           m_CV.notify_one();
+        }
+        
+        /*
+         * retrieve the first element of the queue and remove it
+         * from the queue
+         */
+        T pop_front()
+        {
+            // Wait on queue blocking
+            std::unique_lock<std::mutex> muxLock(m_mutex);
+            while (m_queue.empty())
+            {
+                m_CV.wait(muxLock);
+
+                // If we've been asked to terminate, break out and return
+                // NOTE: the return value is garbage if terminate has been 
+                // called prior this call returning
+                if (m_terminateFlag)
+                {
+                    T elementToReturn;
+                    return elementToReturn;
+                }
+            }
+
+            T elementToReturn = m_queue.front();
+            m_queue.pop();
+            muxLock.unlock();
+            
+            return elementToReturn;
+        }
+
+        /*
+         * retrieve the first element of the queue and remove it
+         * from the queue
+         */
+        T pop_front(bool waitOnEmptyQueue, bool& elementReturned)
+        {
+            // Wait on queue blocking
+            std::unique_lock<std::mutex> muxLock(m_mutex);
+            if (waitOnEmptyQueue)
+            {
+                while (m_queue.empty())
+                {
+                    m_CV.wait(muxLock);
+
+                    // If we've been asked to terminate, break out and return
+                    // NOTE: the return value is garbage if terminate has been 
+                    // called prior this call returning
+                    if (m_terminateFlag)
+                    {
+                        break;
+                    }
+                }
+            }
+
+            T elementToReturn;
+            if (m_queue.size() > 0)
+            {
+                elementReturned = true;
+                elementToReturn = m_queue.front();
+                m_queue.pop();
+            }
+            else
+            {
+                elementReturned = false;
+                elementToReturn = m_queue.front();
+            }
+
+
+            return elementToReturn;
+        }
+        
+        /*
+         * terminate any waiting pop_front() requests
+         */
+        void terminate()   
+        { 
+            m_terminateFlag = true; 
+            m_CV.notify_all(); 
+        }
+        
+        bool empty()
+        {
+            std::lock_guard<std::mutex> lock(m_mutex);
+            return m_queue.empty();
+        }
+        
+        uint64_t size()
+        {
+            std::lock_guard<std::mutex> lock(m_mutex);
+            return m_queue.size();
+        }
+        
+private:
+    bool m_terminateFlag;
+    
+    std::queue<T> m_queue;
+    std::mutex m_mutex;
+    std::condition_variable m_CV;
+    
+};
+
