Поведение хэш-таблицы с использованием glib

#c #linux #hash #hashtable #glib

#c #linux #хэш #хэш-таблица #glib

Вопрос:

Я хочу обновить том до каждого @IP. Так что, например, после каждых 5 секунд я добавляю V (i) каждого @IP (i). Хорошо, теперь хэш-таблица работает нормально, она обновляется каждые T секунд. Но проблема в том, что через определенный период я обнаруживаю, что иногда один и тот же ip-адрес повторяется дважды или даже много раз в хэш-таблице. Так что, когда я закрываю процесс, я обнаруживаю, что один и тот же @IP повторяется слишком много раз. Похоже, что есть проблема с хэш-таблицей или что-то в этом роде.

Вот код, эта функция «update_hashTable()» настолько важна, что вызывается каждые X секунд, я подозреваю, что на самом деле это утечка памяти… потому что я всегда вызываю malloc для IP @. но она продолжает работать… есть идеи???

 int update_hashTable( ... ) {

u_int32_t *a;

... //declarations

struct pf_addr *as;


as = ks->addr[0];

a = (u_int32_t*)malloc(sizeof(u_int32_t));

*a = ntohl(as->addr32[0]);

sz = value; // no matter it is... an int for example

if (ReturnValue=(u_int32_t)g_hash_table_lookup(hashtable, a)) {

  ReturnValue  =sz;
  g_hash_table_insert(hashtable, (gpointer)a, gpointer)ReturnValue);
}
else {
  g_hash_table_insert(hashtable, (gpointer)a, (gpointer)sz);
}
  

Комментарии:

1. В английском языке есть и другие символы препинания, кроме .

Ответ №1:

Действительно, у вас, похоже, утечка памяти, но это не ваша проблема. Проблема в том, что истинный путь вашего оператора if просто повторно вставляет второе значение, связанное с тем же ключом, что не то, что вы хотите.

Типичный шаблон для этого алгоритма проверки, если он существует, и увеличения обычно выглядит примерно так

 gpointer val = g_hash_table_lookup(hash_table, key);
if (val == NULL) {
    val = g_malloc0(...);
    g_hash_table_insert(hash_table, key, val);
}
*val = /* something */;
  

Из этого следует извлечь важную вещь: как только у вас есть указатель на значение, связанное с некоторым ключом, вы можете просто изменить его напрямую.

Если этот код будет выполняться несколькими потоками параллельно, тогда весь блок должен быть защищен мьютексом, возможно, с помощью GMutex: http://developer.gnome.org/glib/2.28/glib-Threads.html

gcc предоставляет атомарные встроенные функции, скажем, для атомарного увеличения значения, см. http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html

Комментарии:

1. как только у вас есть указатель на значение, связанное с некоторым ключом, вы можете просто изменить его напрямую. Это действительно поможет мне, спасибо. Но у меня есть 2 замечания по поводу того, что вы написали: 1) val = g_malloc0(…); g_hash_table_insert(hash_table, key, val); кажется, что значение val не инициализируется с 0, хотя вы использовали g_malloc0 … Когда я выполняю программу, она выдает некоторую случайную величину. 2) насчет ` val` это не сработало, потому что фактически указывает на пустоту. Я использовал вместо этого: * (u_int32_t*)val) = sz (sz — это u_int32_t) но на самом деле все идет не так, как вы сказали: * как только у вас есть указатель на ассоциированное значение …

2. Да, конечно, вам придется использовать *val, чтобы присвоить ее значение. Предполагалось, что вы сможете управлять этой частью без явного указания этого, поскольку вопрос касался glib, а не C. В любом случае, я, кажется, ответил на заданный вопрос, поэтому, пожалуйста, примите мой ответ.