系列文章目录
文章目录
前言
总结一下cv::Mat 中的引用计数。
一、引用计数是什么?
引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。使用引用计数技术可以实现自动资源管理的目的。同时引用计数还可以指使用引用计数技术回收未使用资源的垃圾回收算法。
好巧不巧,c++语言并不支持原生的垃圾回收,至少到目前的c++20版本是如此。opencv实现了引用计数。使用满足并发的原子操作交换加法。(exchange-add operation for atomic operations on reference counters)
作为支持指针的编程语言,C++将动态管理存储器资源的便利性交给了程序员。在使用指针形式的对象时(请注意,由于引用在初始化后不能更改引用目标的语言机制的限制,多态性应用大多数情况下依赖于指针进行),程序员必须自己完成存储器的分配、使用和释放,语言本身在此过程中不能提供任何帮助,也许除了按照你的要求正确的和操作系统亲密合作,完成实际的存储器管理。标准文本中,多次提到了“未定义(undefined)”,而这大多数情况下和指针相关。
某些语言提供了垃圾回收机制,也就是说程序员仅负责分配存储器和使用,而由语言本身负责释放不再使用的存储器,这样程序员就从讨厌的存储器管理的工作中脱身了。然而C++并没有提供类似的机制。
二、opencv的实现
1.cvdef.h
/****************************************************************************************\
* exchange-add operation for atomic operations on reference counters *
\****************************************************************************************/
#ifdef CV_XADD
// allow to use user-defined macro
#elif defined __GNUC__ || defined __clang__
# if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) && !defined __INTEL_COMPILER
# ifdef __ATOMIC_ACQ_REL
# define CV_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL)
# else
# define CV_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4)
# endif
# else
# if defined __ATOMIC_ACQ_REL && !defined __clang__
// version for gcc >= 4.7
# define CV_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL)
# else
# define CV_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta))
# endif
# endif
#elif defined _MSC_VER && !defined RC_INVOKED
# include <intrin.h>
# define CV_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta)
#else
#ifdef OPENCV_FORCE_UNSAFE_XADD
CV_INLINE CV_XADD(int* addr, int delta) { int tmp = *addr; *addr += delta; return tmp; }
#else
#error "OpenCV: can't define safe CV_XADD macro for current platform (unsupported). Define CV_XADD macro through custom port header (see OPENCV_INCLUDE_PORT_FILE)"
#endif
#endif
对于GCC, 实际是: define CV_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL)
gcc的原子操作实现均符合c++11定义的原子操作6种内存模型:
__ATOMIC_RELAXED No barriers or synchronization.
__ATOMIC_CONSUME Data dependency only for both barrier and synchronization with another thread.
__ATOMIC_ACQUIRE Barrier to hoisting of code and synchronizes with release (or stronger) semantic stores from another thread.
__ATOMIC_RELEASE Barrier to sinking of code and synchronizes with acquire (or stronger) semantic loads from another thread.
__ATOMIC_ACQ_REL Full barrier in both directions and synchronizes with acquire loads and release stores in another thread.
__ATOMIC_SEQ_CST Full barrier in both directions and synchronizes with acquire loads and release stores in all threads.
详见 http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
gcc的内置原子函数:
定义见 http://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
定义列表:
— Built-in Function: type __atomic_load_n (type *ptr, int memmodel)
— Built-in Function: void __atomic_load (type *ptr, type *ret, int memmodel)
— Built-in Function: void __atomic_store_n (type *ptr, type val, int memmodel)
— Built-in Function: void __atomic_store (type *ptr, type *val, int memmodel)
— Built-in Function: type __atomic_exchange_n (type *ptr, type val, int memmodel)
— Built-in Function: void __atomic_exchange (type *ptr, type *val, type *ret, int memmodel)
— Built-in Function: bool __atomic_compare_exchange_n (type *ptr, type *expected, type desired, bool weak, int success_memmodel, int failure_memmodel)
— Built-in Function: bool __atomic_compare_exchange (type *ptr, type *expected, type *desired, bool
— Built-in Function: type __atomic_add_fetch (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_sub_fetch (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_and_fetch (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_xor_fetch (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_or_fetch (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_nand_fetch (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_fetch_add (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_fetch_sub (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_fetch_and (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_fetch_xor (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_fetch_or (type *ptr, type val, int memmodel)
— Built-in Function: type __atomic_fetch_nand (type *ptr, type val, int memmodel)
— Built-in Function: bool __atomic_test_and_set (void *ptr, int memmodel)
— Built-in Function: void __atomic_clear (bool *ptr, int memmodel)
— Built-in Function: void __atomic_thread_fence (int memmodel)
— Built-in Function: void __atomic_signal_fence (int memmodel)
— Built-in Function: bool __atomic_always_lock_free (size_t size, void *ptr)
— Built-in Function: bool __atomic_is_lock_free (size_t size, void *ptr)
2.UMat
除了CV_XADD(),还有release() , addref()
UMat的成员UMatData * u,具有int refcount ; int urefcount;
inline
void Mat::addref()
{
if( u )
CV_XADD(&u->refcount, 1);
}
inline
void Mat::release()
{
if( u && CV_XADD(&u->refcount, -1) == 1 )
deallocate();
u = NULL;
datastart = dataend = datalimit = data = 0;
for(int i = 0; i < dims; i++)
size.p[i] = 0;
#ifdef _DEBUG
flags = MAGIC_VAL;
dims = rows = cols = 0;
if(step.p != step.buf)
{
fastFree(step.p);
step.p = step.buf;
size.p = &rows;
}
#endif
}