Add atomically reference counted memory

Similar to g_ref_*, we have g_atomic_ref_*, which will ensure that all
reference counting operations are performed atomically.

Not every data structure needs atomic reference counting; for instance,
most of the GTK+ data structures operate under the assumption that only
one thread can access windowing system data. Since atomic operations are
not cheap, forcing them on every data structure can negatively affect
performance.

The underlying reference counting mechanism for g_atomic_ref_* is the
same as for g_ref_*, but instead of adding a "make this atomic" boolean
flag to the g_ref_* API we prefer being explicit, and add the "atomic"
qualifier directly into the API, to avoid misunderstandings.
This commit is contained in:
Emmanuele Bassi 2016-11-15 12:40:41 +00:00
parent b49fd4c730
commit 43ed42e4d5
2 changed files with 78 additions and 0 deletions

View File

@ -326,3 +326,60 @@ g_ref_release (gpointer ref)
if (g_ref_counter_release (&real_ref->ref_count)) if (g_ref_counter_release (&real_ref->ref_count))
g_ref_free (ref); g_ref_free (ref);
} }
gpointer
g_atomic_ref_alloc (gsize size,
GDestroyNotify notify)
{
g_return_val_if_fail (size > 0, NULL);
return g_ref_alloc_internal (size, FALSE, TRUE, notify);
}
gpointer
g_atomic_ref_alloc0 (gsize size,
GDestroyNotify notify)
{
g_return_val_if_fail (size > 0, NULL);
return g_ref_alloc_internal (size, TRUE, TRUE, notify);
}
gpointer
g_atomic_ref_dup (gconstpointer data,
gsize size,
GDestroyNotify notify)
{
gpointer res;
g_return_val_if_fail (size > 0, NULL);
res = g_ref_alloc_internal (size, FALSE, TRUE, notify);
memcpy (res, data, size);
return res;
}
gpointer
g_atomic_ref_acquire (gpointer ref)
{
GRef *real_ref = G_REF (ref);
g_return_val_if_fail (ref != NULL, NULL);
g_ref_counter_acquire (&real_ref->ref_count);
return ref;
}
void
g_atomic_ref_release (gpointer ref)
{
GRef *real_ref = G_REF (ref);
g_return_if_fail (ref != NULL);
if (g_ref_counter_release (&real_ref->ref_count))
g_ref_free (ref);
}

View File

@ -59,6 +59,27 @@ gpointer g_ref_acquire (gpointer ref);
GLIB_AVAILABLE_IN_2_52 GLIB_AVAILABLE_IN_2_52
void g_ref_release (gpointer ref); void g_ref_release (gpointer ref);
#define g_atomic_ref_new(Type,Notify) \
(Type *) g_atomic_ref_alloc (sizeof (Type), Notify)
#define g_atomic_ref_new0(Type,Notify) \
(Type *) g_atomic_ref_alloc0 (sizeof (Type), Notify)
GLIB_AVAILABLE_IN_2_52
gpointer g_atomic_ref_alloc (gsize size,
GDestroyNotify notify);
GLIB_AVAILABLE_IN_2_52
gpointer g_atomic_ref_alloc0 (gsize size,
GDestroyNotify notify);
GLIB_AVAILABLE_IN_2_52
gpointer g_atomic_ref_dup (gconstpointer data,
gsize size,
GDestroyNotify notify);
GLIB_AVAILABLE_IN_2_52
gpointer g_atomic_ref_acquire (gpointer ref);
GLIB_AVAILABLE_IN_2_52
void g_atomic_ref_release (gpointer ref);
G_END_DECLS G_END_DECLS
#endif /* __G_REF_COUNT_H__ */ #endif /* __G_REF_COUNT_H__ */