init
This commit is contained in:
235
OpenCV/include/opencv2/core/utils/tls.hpp
Normal file
235
OpenCV/include/opencv2/core/utils/tls.hpp
Normal file
@@ -0,0 +1,235 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef OPENCV_UTILS_TLS_HPP
|
||||
#define OPENCV_UTILS_TLS_HPP
|
||||
|
||||
#ifndef OPENCV_CORE_UTILITY_H
|
||||
#error "tls.hpp must be included after opencv2/core/utility.hpp or opencv2/core.hpp"
|
||||
#endif
|
||||
|
||||
namespace cv {
|
||||
|
||||
//! @addtogroup core_utils
|
||||
//! @{
|
||||
|
||||
namespace details { class TlsStorage; }
|
||||
|
||||
/** TLS container base implementation
|
||||
*
|
||||
* Don't use directly.
|
||||
*
|
||||
* @sa TLSData, TLSDataAccumulator templates
|
||||
*/
|
||||
class CV_EXPORTS TLSDataContainer
|
||||
{
|
||||
protected:
|
||||
TLSDataContainer();
|
||||
virtual ~TLSDataContainer();
|
||||
|
||||
/// @deprecated use detachData() instead
|
||||
void gatherData(std::vector<void*> &data) const;
|
||||
/// get TLS data and detach all data from threads (similar to cleanup() call)
|
||||
void detachData(std::vector<void*>& data);
|
||||
|
||||
void* getData() const;
|
||||
void release();
|
||||
|
||||
protected:
|
||||
virtual void* createDataInstance() const = 0;
|
||||
virtual void deleteDataInstance(void* pData) const = 0;
|
||||
|
||||
private:
|
||||
int key_;
|
||||
|
||||
friend class cv::details::TlsStorage; // core/src/system.cpp
|
||||
|
||||
public:
|
||||
void cleanup(); //!< Release created TLS data container objects. It is similar to release() call, but it keeps TLS container valid.
|
||||
|
||||
private:
|
||||
// Disable copy/assign (noncopyable pattern)
|
||||
TLSDataContainer(TLSDataContainer &) = delete;
|
||||
TLSDataContainer& operator =(const TLSDataContainer &) = delete;
|
||||
};
|
||||
|
||||
|
||||
/** @brief Simple TLS data class
|
||||
*
|
||||
* @sa TLSDataAccumulator
|
||||
*/
|
||||
template <typename T>
|
||||
class TLSData : protected TLSDataContainer
|
||||
{
|
||||
public:
|
||||
inline TLSData() {}
|
||||
inline ~TLSData() { release(); }
|
||||
|
||||
inline T* get() const { return (T*)getData(); } //!< Get data associated with key
|
||||
inline T& getRef() const { T* ptr = (T*)getData(); CV_DbgAssert(ptr); return *ptr; } //!< Get data associated with key
|
||||
|
||||
/// Release associated thread data
|
||||
inline void cleanup()
|
||||
{
|
||||
TLSDataContainer::cleanup();
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Wrapper to allocate data by template
|
||||
virtual void* createDataInstance() const CV_OVERRIDE { return new T; }
|
||||
/// Wrapper to release data by template
|
||||
virtual void deleteDataInstance(void* pData) const CV_OVERRIDE { delete (T*)pData; }
|
||||
};
|
||||
|
||||
|
||||
/// TLS data accumulator with gathering methods
|
||||
template <typename T>
|
||||
class TLSDataAccumulator : public TLSData<T>
|
||||
{
|
||||
mutable cv::Mutex mutex;
|
||||
mutable std::vector<T*> dataFromTerminatedThreads;
|
||||
std::vector<T*> detachedData;
|
||||
bool cleanupMode;
|
||||
public:
|
||||
TLSDataAccumulator() : cleanupMode(false) {}
|
||||
~TLSDataAccumulator()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
/** @brief Get data from all threads
|
||||
* @deprecated replaced by detachData()
|
||||
*
|
||||
* Lifetime of vector data is valid until next detachData()/cleanup()/release() calls
|
||||
*
|
||||
* @param[out] data result buffer (should be empty)
|
||||
*/
|
||||
void gather(std::vector<T*> &data) const
|
||||
{
|
||||
CV_Assert(cleanupMode == false); // state is not valid
|
||||
CV_Assert(data.empty());
|
||||
{
|
||||
std::vector<void*> &dataVoid = reinterpret_cast<std::vector<void*>&>(data);
|
||||
TLSDataContainer::gatherData(dataVoid);
|
||||
}
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
data.reserve(data.size() + dataFromTerminatedThreads.size());
|
||||
for (typename std::vector<T*>::const_iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i)
|
||||
{
|
||||
data.push_back((T*)*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Get and detach data from all threads
|
||||
*
|
||||
* Call cleanupDetachedData() when returned vector is not needed anymore.
|
||||
*
|
||||
* @return Vector with associated data. Content is preserved (including lifetime of attached data pointers) until next detachData()/cleanupDetachedData()/cleanup()/release() calls
|
||||
*/
|
||||
std::vector<T*>& detachData()
|
||||
{
|
||||
CV_Assert(cleanupMode == false); // state is not valid
|
||||
std::vector<void*> dataVoid;
|
||||
{
|
||||
TLSDataContainer::detachData(dataVoid);
|
||||
}
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
detachedData.reserve(dataVoid.size() + dataFromTerminatedThreads.size());
|
||||
for (typename std::vector<T*>::const_iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i)
|
||||
{
|
||||
detachedData.push_back((T*)*i);
|
||||
}
|
||||
dataFromTerminatedThreads.clear();
|
||||
for (typename std::vector<void*>::const_iterator i = dataVoid.begin(); i != dataVoid.end(); ++i)
|
||||
{
|
||||
detachedData.push_back((T*)(void*)*i);
|
||||
}
|
||||
}
|
||||
dataVoid.clear();
|
||||
return detachedData;
|
||||
}
|
||||
|
||||
/// Release associated thread data returned by detachData() call
|
||||
void cleanupDetachedData()
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
cleanupMode = true;
|
||||
_cleanupDetachedData();
|
||||
cleanupMode = false;
|
||||
}
|
||||
|
||||
/// Release associated thread data
|
||||
void cleanup()
|
||||
{
|
||||
cleanupMode = true;
|
||||
TLSDataContainer::cleanup();
|
||||
|
||||
AutoLock lock(mutex);
|
||||
_cleanupDetachedData();
|
||||
_cleanupTerminatedData();
|
||||
cleanupMode = false;
|
||||
}
|
||||
|
||||
/// Release associated thread data and free TLS key
|
||||
void release()
|
||||
{
|
||||
cleanupMode = true;
|
||||
TLSDataContainer::release();
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
_cleanupDetachedData();
|
||||
_cleanupTerminatedData();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// synchronized
|
||||
void _cleanupDetachedData()
|
||||
{
|
||||
for (typename std::vector<T*>::iterator i = detachedData.begin(); i != detachedData.end(); ++i)
|
||||
{
|
||||
deleteDataInstance((T*)*i);
|
||||
}
|
||||
detachedData.clear();
|
||||
}
|
||||
|
||||
// synchronized
|
||||
void _cleanupTerminatedData()
|
||||
{
|
||||
for (typename std::vector<T*>::iterator i = dataFromTerminatedThreads.begin(); i != dataFromTerminatedThreads.end(); ++i)
|
||||
{
|
||||
deleteDataInstance((T*)*i);
|
||||
}
|
||||
dataFromTerminatedThreads.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void* createDataInstance() const CV_OVERRIDE
|
||||
{
|
||||
// Note: we can collect all allocated data here, but this would require raced mutex locks
|
||||
return new T;
|
||||
}
|
||||
virtual void deleteDataInstance(void* pData) const CV_OVERRIDE
|
||||
{
|
||||
if (cleanupMode)
|
||||
{
|
||||
delete (T*)pData;
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoLock lock(mutex);
|
||||
dataFromTerminatedThreads.push_back((T*)pData);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//! @}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // OPENCV_UTILS_TLS_HPP
|
||||
Reference in New Issue
Block a user