Подсчет ссылок не так уж и сложен:
aStruct *astruct_getref(aStruct *m)
{
m->refs++;
return m;
}
aStruct *astruct_new(void)
{
sStruct *new = calloc(1, sizeof *new);
return astruct_getref(new);
}
void astruct_free(aStruct *m)
{
if (--m->refs == 0)
free(m);
}
(В многопоточной среде вам также может понадобиться добавить блокировку).
Тогда ваш код будет:
aStruct *A = NULL, *B = NULL;
A = astruct_new();
B = astruct_getref(A);
astruct_free(A);
...
//bunch of other code in various places.
...
astruct_free(B);
Вы спрашивали о блокировке. К сожалению, нет единого универсального ответа, когда дело доходит до блокировки - все зависит от того, какие шаблоны доступа есть в вашем приложении. Там нет замены для тщательного проектирования и глубоких мыслей. (Например, если вы можете гарантировать , что ни один поток не будет вызывать astruct_getref()
или astruct_free()
для aStruct
другого потока, тогда счетчик ссылок вообще не нужно защищать - простой реализации выше будет достаточно).
Тем не менее, вышеуказанные примитивы могут быть легко расширены для поддержки одновременного доступа к функциям astruct_getref()
и astruct_free()
:
aStruct *astruct_getref(aStruct *m)
{
mutex_lock(m->reflock);
m->refs++;
mutex_unlock(m->reflock);
return m;
}
aStruct *astruct_new(void)
{
sStruct *new = calloc(1, sizeof *new);
mutex_init(new->reflock);
return astruct_getref(new);
}
void astruct_free(aStruct *m)
{
int refs;
mutex_lock(m->reflock);
refs = --m->refs;
mutex_unlock(m->reflock);
if (refs == 0)
free(m);
}
... но обратите внимание, что любые переменные, содержащие указатели на структуры, которые подлежат одновременному доступу, также потребуют своей собственной блокировки (например, если у вас есть глобальный aStruct *foo
, к которому одновременно осуществляется доступ, ему потребуется сопровождающий foo_lock
).