changeset 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents ef14acd6d102
children 6441b31b37ac
files data/fft/FFTFileCache.cpp data/fft/FFTFileCache.h
diffstat 2 files changed, 28 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/data/fft/FFTFileCache.cpp	Tue Oct 14 16:36:35 2008 +0000
+++ b/data/fft/FFTFileCache.cpp	Wed Oct 15 12:08:02 2008 +0000
@@ -72,16 +72,21 @@
     MutexLocker locker(&m_writeMutex, "FFTFileCache::resize::m_writeMutex");
 
     m_mfc->resize(width, height * 2 + m_factorSize);
-    if (m_readbuf) {
-        delete[] m_readbuf;
-        m_readbuf = 0;
+
+    {
+        MutexLocker locker(&m_readbufMutex, "FFTFileCache::resize::m_readMutex");
+        if (m_readbuf) {
+            delete[] m_readbuf;
+            m_readbuf = 0;
+        }
     }
+
     if (m_writebuf) {
         delete[] m_writebuf;
     }
     m_writebuf = new char[(height * 2 + m_factorSize) * m_mfc->getCellSize()];
 }
-
+    
 void
 FFTFileCache::reset()
 {
@@ -302,7 +307,7 @@
 }
 
 void
-FFTFileCache::populateReadBuf(size_t x) const
+FFTFileCache::populateReadBuf(size_t x) const // m_readbufMutex already held
 {
     Profiler profiler("FFTFileCache::populateReadBuf", false);
 
--- a/data/fft/FFTFileCache.h	Tue Oct 14 16:36:35 2008 +0000
+++ b/data/fft/FFTFileCache.h	Wed Oct 15 12:08:02 2008 +0000
@@ -62,31 +62,43 @@
     mutable size_t m_readbufWidth;
 
     float getFromReadBufStandard(size_t x, size_t y) const {
+        m_readbufMutex.lock();
         if (m_readbuf &&
             (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) {
-            return ((float *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y];
+            float v = ((float *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y];
+            m_readbufMutex.unlock();
+            return v;
         } else {
             populateReadBuf(x);
+            m_readbufMutex.unlock();
             return getFromReadBufStandard(x, y);
         }
     }
 
     float getFromReadBufCompactUnsigned(size_t x, size_t y) const {
+        m_readbufMutex.lock();
         if (m_readbuf &&
             (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) {
-            return ((uint16_t *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y];
+            float v = ((uint16_t *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y];
+            m_readbufMutex.unlock();
+            return v;
         } else {
             populateReadBuf(x);
+            m_readbufMutex.unlock();
             return getFromReadBufCompactUnsigned(x, y);
         }
     }
 
     float getFromReadBufCompactSigned(size_t x, size_t y) const {
+        m_readbufMutex.lock();
         if (m_readbuf &&
             (m_readbufCol == x || (m_readbufWidth > 1 && m_readbufCol+1 == x))) {
-            return ((int16_t *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y];
+            float v = ((int16_t *)m_readbuf)[(x - m_readbufCol) * m_mfc->getHeight() + y];
+            m_readbufMutex.unlock();
+            return v;
         } else {
             populateReadBuf(x);
+            m_readbufMutex.unlock();
             return getFromReadBufCompactSigned(x, y);
         }
     }
@@ -99,6 +111,7 @@
         if (m_storageType != Compact) {
             return getFromReadBufStandard(col, h - 1);
         } else {
+            m_readbufMutex.lock();
             union {
                 float f;
                 uint16_t u[2];
@@ -111,6 +124,7 @@
             size_t ix = (col - m_readbufCol) * m_mfc->getHeight() + h;
             factor.u[0] = ((uint16_t *)m_readbuf)[ix - 2];
             factor.u[1] = ((uint16_t *)m_readbuf)[ix - 1];
+            m_readbufMutex.unlock();
             return factor.f;
         }
     }
@@ -133,6 +147,7 @@
 
     MatrixFile *m_mfc;
     QMutex m_writeMutex;
+    mutable QMutex m_readbufMutex;
     StorageType m_storageType;
     size_t m_factorSize;
 };