c++-gtk-utils
Public Member Functions | List of all members
Cgu::SharedLockHandle< T, Dealloc > Class Template Reference

This is a generic class for managing the lifetime of objects allocated on freestore, with a thread safe reference count.. More...

#include <c++-gtk-utils/shared_handle.h>

Public Member Functions

 SharedLockHandle (T ptr=0)
 
 SharedLockHandle (T ptr, Cgu::SharedHandleAllocFail::Leave tag)
 
void reset (T ptr=0)
 
void reset (T ptr, Cgu::SharedHandleAllocFail::Leave tag)
 
 SharedLockHandle (const SharedLockHandle &sh_hand)
 
SharedLockHandleoperator= (SharedLockHandle sh_hand)
 
get () const
 
 operator T () const
 
unsigned int get_refcount () const
 
 ~SharedLockHandle ()
 

Detailed Description

template<class T, class Dealloc = StandardArrayDelete<T>>
class Cgu::SharedLockHandle< T, Dealloc >

This is a generic class for managing the lifetime of objects allocated on freestore, with a thread safe reference count..

See also
SharedHandle ScopedHandle SharedHandleError
StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy

Class SharedLockHandle is a version of the SharedHandle class which includes synchronization so that it can handle objects accessed in multiple threads (although the word Lock is in the title, by default it uses glib atomic functions to access the reference count rather than a mutex, so the overhead should be very small). Note that only the reference count is protected, so this is thread safe in the sense in which a raw pointer is thread safe. A shared handle accessed in one thread referencing a particular object is thread safe as against another shared handle accessing the same object in a different thread. It is thus suitable for use in different standard C++ containers which exist in different threads but which contain shared objects by reference. But:

  1. If the referenced object is to be modified in one thread and read or modified in another thread an appropriate mutex for the referenced object is required (unless that referenced object does its own locking).
  2. If the same instance of shared handle is to be modified in one thread (by assigning to the handle so that it references a different object), and copied (assigned from or used as the argument of a copy constructor), accessed, destroyed or modified in another thread, a mutex for that instance of shared handle is required.
  3. Objects referenced by shared handles which are objects for which POSIX provides no guarantees (in the main, those which are not built-in types), such as strings and similar containers, may not support concurrent reads in different threads. That depends on the library implementation concerned. If that is the case, a mutex for the referenced object will also be required when reading any given instance of such an object in more than one thread by dereferencing any shared handles referencing it (and indeed, when not using shared handles at all).

As of version 1.0.2, SharedLockHandle objects can be instantiated for pointers to constant objects (such as SharedLockHandle<const char*>), provided the deleter functor will take such pointers. Prior to version 1.0.2, it could only manage pointers to non-const objects.

This library provides StandardArrayDelete, CFree, GFree, GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter functors, which can be used as the second template parameter of the SharedLockHandle class. StandardArrayDelete is the default.

As mentioned, by default glib atomic functions are used to provide thread-safe manipulation of the reference count. However, from version 1.2.0 the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX can be defined so that the library uses mutexes instead, which might be useful for some debugging purposes. Note that if CGU_SHARED_LOCK_HANDLE_USE_MUTEX is to be defined, this is best done by textually amending the shared_handle.h header file before the library is compiled. This will ensure that everything in the program and the library which includes the shared_handle.h header is guaranteed to see the same definitions so that the C++ standard's one-definition-rule is complied with.

From version 1.2.12, the library provides ==, != and < comparison operators for SharedLockHandles, but only if the library is compiled with the --with-smart-ptr-comp option, or if the user code defines the symbol CGU_USE_SMART_PTR_COMPARISON before shared_handle.h is first parsed. This is because, if user code has provided such operators for these smart pointers itself, a duplicated function definition would arise.

If the library is compiled with the --with-glib-memory-slices-no-compat configuration option, Cgu::SharedLockHandle constructs its reference counting internals using glib memory slices. Although it is safe in a multi-threaded program if glib < 2.32 is installed to construct a static SharedLockHandle object in global namespace (that is, prior to g_thread_init() being called) by means of the default constructor and/or a pointer argument of NULL, it is not safe if constructed with a non-NULL pointer value. If glib >= 2.32 is installed, global objects with memory slices are safe in all circumstances. (Having said that, it would be highly unusual to have global SharedLockHandle objects.)

Constructor & Destructor Documentation

◆ SharedLockHandle() [1/3]

template<class T , class Dealloc = StandardArrayDelete<T>>
Cgu::SharedLockHandle< T, Dealloc >::SharedLockHandle ( ptr = 0)
inlineexplicit

Constructor taking an unmanaged object.

Parameters
ptrThe object which the SharedLockHandle is to manage (if any).
Exceptions
std::bad_allocThis constructor will not throw if the 'ptr' argument has a NULL value (the default), otherwise it might throw std::bad_alloc if memory is exhausted and the system throws in that case. If such an exception is thrown, this constructor is exception safe (it does not leak resources), but as well as cleaning itself up this constructor will also delete the managed object passed to it to avoid a memory leak. If such automatic deletion is not wanted in that case, use the version of this constructor taking a Cgu::SharedHandleAllocFail::Leave tag argument.
Note
1. std::bad_alloc will not be thrown if the library has been installed using the --with-glib-memory-slices-no-compat configuration option: instead glib will terminate the program if it is unable to obtain memory from the operating system.
2. By default, glib atomic functions are used to provide thread-safe manipulation of the reference count. However, from version 1.2.0 the header file shared_handle.h can be textually amended before the library is compiled to define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX so as to use mutexes instead, which might be useful for some debugging purposes. Were that to be done, Cgu::Thread::MutexError might be thrown by this constructor if initialization of the mutex fails.

Since 1.0.2, SharedLockHandle objects can be instantiated for pointers to constant objects (such as SharedLockHandle<const char*>), provided the deleter functor will take such pointers. Prior to version 1.0.2, it could only manage pointers to non-const objects.

◆ SharedLockHandle() [2/3]

template<class T , class Dealloc = StandardArrayDelete<T>>
Cgu::SharedLockHandle< T, Dealloc >::SharedLockHandle ( ptr,
Cgu::SharedHandleAllocFail::Leave  tag 
)
inline

Constructor taking an unmanaged object.

Parameters
ptrThe object which the SharedLockHandle is to manage.
tagPassing the tag emumerator Cgu::SharedHandleAllocFail::leave causes this constructor not to delete the new managed object passed as the 'ptr' argument in the event of internal allocation in this method failing because of memory exhaustion (in that event, Cgu::SharedHandleError will be thrown).
Exceptions
Cgu::SharedHandleErrorThis constructor might throw Cgu::SharedHandleError if memory is exhausted and the system would otherwise throw std::bad_alloc in that case. This constructor is exception safe (it does not leak resources), and if such an exception is thrown it will clean itself up, but it will not attempt to delete the new managed object passed to it. Access to the object passed to the 'ptr' argument can be obtained via the thrown Cgu::SharedHandleError object.
Note
1. On systems with over-commit/lazy-commit combined with virtual memory (swap), it is rarely useful to check for memory exhaustion, so in those cases this version of the constructor will not be useful.
2. If the library has been installed using the --with-glib-memory-slices-no-compat configuration option this version of the constructor will also not be useful: instead glib will terminate the program if it is unable to obtain memory from the operating system.
3. By default, glib atomic functions are used to provide thread-safe manipulation of the reference count. However, from version 1.2.0 the header file shared_handle.h can be textually amended before the library is compiled to define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX so as to use mutexes instead, which might be useful for some debugging purposes. Were that to be done, Cgu::SharedHandleError might be thrown by this constructor if initialization of the mutex fails (even if the --with-glib-memory-slices-no-compat configuration option is chosen).

Since 0.9.1 (first version in which this constructor available).

Since 1.0.2, SharedLockHandle objects can be instantiated for pointers to constant objects (such as SharedLockHandle<const char*>), provided the deleter functor will take such pointers. Prior to version 1.0.2, it could only manage pointers to non-const objects.

◆ SharedLockHandle() [3/3]

template<class T , class Dealloc = StandardArrayDelete<T>>
Cgu::SharedLockHandle< T, Dealloc >::SharedLockHandle ( const SharedLockHandle< T, Dealloc > &  sh_hand)
inline

The copy constructor does not throw.

Parameters
sh_handThe handle to be copied.

◆ ~SharedLockHandle()

template<class T , class Dealloc = StandardArrayDelete<T>>
Cgu::SharedLockHandle< T, Dealloc >::~SharedLockHandle ( )
inline

The destructor does not throw unless the destructor of a handled object throws - that should never happen.

Member Function Documentation

◆ get()

template<class T , class Dealloc = StandardArrayDelete<T>>
T Cgu::SharedLockHandle< T, Dealloc >::get ( ) const
inline

This method does not throw.

Returns
A pointer to the handled object (or NULL if none is handled).

◆ get_refcount()

template<class T , class Dealloc = StandardArrayDelete<T>>
unsigned int Cgu::SharedLockHandle< T, Dealloc >::get_refcount ( ) const
inline

This method does not throw.

Returns
The number of SharedLockHandle objects referencing the managed object (or 0 if none is managed by this SharedLockHandle).
Note
The return value may not be valid if another thread has changed the reference count before the value returned by this method is acted on. It is provided as a utility, but may not be meaningful, depending on the intended usage.

◆ operator T()

template<class T , class Dealloc = StandardArrayDelete<T>>
Cgu::SharedLockHandle< T, Dealloc >::operator T ( ) const
inline

This method does not throw.

Returns
A pointer to the handled object (or NULL if none is handled).

◆ operator=()

template<class T , class Dealloc = StandardArrayDelete<T>>
SharedLockHandle& Cgu::SharedLockHandle< T, Dealloc >::operator= ( SharedLockHandle< T, Dealloc >  sh_hand)
inline

This method does not throw unless the destructor of a handled object throws.

Parameters
sh_handthe assignor.
Returns
The SharedLockHandle object after assignment.

◆ reset() [1/2]

template<class T , class Dealloc = StandardArrayDelete<T>>
void Cgu::SharedLockHandle< T, Dealloc >::reset ( ptr,
Cgu::SharedHandleAllocFail::Leave  tag 
)
inline

Causes the SharedLockHandle to cease to manage its managed object (if any), deleting it if this is the last ShareLockHandle object managing it. The SharedLockHandle object will manage the new object passed (which must not be managed by any other SharedLockHandle object). This method is exception safe, but see the comments below on Cgu::SharedHandleError.

Parameters
ptrA new unmanaged object to manage (if no new object is to be managed, use the version of reset() taking a default value of NULL).
tagPassing the tag emumerator Cgu::SharedHandleAllocFail::leave causes this method not to delete the new managed object passed as the 'ptr' argument in the event of internal allocation in this method failing because of memory exhaustion (in that event, Cgu::SharedHandleError will be thrown).
Exceptions
Cgu::SharedHandleErrorThis method might throw Cgu::SharedHandleError if memory is exhausted and the system would otherwise throw std::bad_alloc in that case. Note that if such an exception is thrown then this method will do nothing (it is strongly exception safe and will continue to manage the object it was managing prior to the call), and it will not attempt to delete the new managed object passed to it (if any). Access to the object passed to the 'ptr' argument can be obtained via the thrown Cgu::SharedHandleError object.
Note
1. A SharedLockHandle object protects its reference count but not the managed object or its other internals. The reset() method should not be called by one thread in respect of a particular SharedLockHandle object while another thread may be operating on, copying or dereferencing the same instance of SharedLockHandle. It is thread-safe as against another instance of SharedLockHandle managing the same object.
2. On systems with over-commit/lazy-commit combined with virtual memory (swap), it is rarely useful to check for memory exhaustion, so in those cases this version of the reset() method will not be useful.
3. If the library has been installed using the --with-glib-memory-slices-no-compat configuration option this version of the reset() method will also not be useful: instead glib will terminate the program if it is unable to obtain memory from the operating system.
4. By default, glib atomic functions are used to provide thread-safe manipulation of the reference count. However, from version 1.2.0 the header file shared_handle.h can be textually amended before the library is compiled to define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX so as to use mutexes instead, which might be useful for some debugging purposes. Were that to be done, Cgu::SharedHandleError might be thrown by this method if initialization of the mutex fails (even if the --with-glib-memory-slices-no-compat configuration option is chosen).

Since 0.9.1

◆ reset() [2/2]

template<class T , class Dealloc = StandardArrayDelete<T>>
void Cgu::SharedLockHandle< T, Dealloc >::reset ( ptr = 0)
inline

Causes the SharedLockHandle to cease to manage its managed object (if any), deleting it if this is the last ShareLockHandle object managing it. If the argument passed is not NULL, the SharedLockHandle object will manage the new object passed (which must not be managed by any other SharedLockHandle object).

Parameters
ptrNULL (the default), or a new unmanaged object to manage.
Exceptions
std::bad_allocThis method will not throw if the 'ptr' argument has a NULL value (the default) and the destructor of a managed object does not throw, otherwise it might throw std::bad_alloc if memory is exhausted and the system throws in that case. Note that if such an exception is thrown then this method will do nothing (it is strongly exception safe and will continue to manage the object it was managing prior to the call), except that it will delete the new managed object passed to it to avoid a memory leak. If such automatic deletion in the event of such an exception is not wanted, use the reset() method taking a Cgu::SharedHandleAllocFail::Leave tag type as its second argument.
Note
1. std::bad_alloc will not be thrown if the library has been installed using the --with-glib-memory-slices-no-compat configuration option: instead glib will terminate the program if it is unable to obtain memory from the operating system.
2. By default, glib atomic functions are used to provide thread-safe manipulation of the reference count. However, from version 1.2.0 the header file shared_handle.h can be textually amended before the library is compiled to define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX so as to use mutexes instead, which might be useful for some debugging purposes. Were that to be done, Cgu::Thread::MutexError might be thrown by this method if initialization of the mutex fails.
3. A SharedLockHandle object protects its reference count but not the managed object or its other internals. The reset() method should not be called by one thread in respect of a particular SharedLockHandle object while another thread may be operating on, copying or dereferencing the same instance of SharedLockHandle. It is thread-safe as against another instance of SharedLockHandle managing the same object.

Since 0.9.1


The documentation for this class was generated from the following file: