DavidLeeds / hashmap

Templated type-safe hashmap implementation in C using open addressing and linear probing for collision resolution.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Traversal error while adding

fancong5201314 opened this issue · comments

When I was using the test program, I added elements while traversing, and found that I always traversed to the last element each time, adding and deleting at the same time. This is my test program.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <libgen.h>
#include <errno.h>
#include <pthread.h>

#include "hashmap.h"

#define ERROR(format, args...)  do{printf("\033[1;31m[TEST][%s-%d]\033[m" format, basename(__FILE__), __LINE__, ##args);}while(0)
#define DEBUG(format, args...)  do{printf("\033[1;32m[TEST][%s-%d]\033[m" format, basename(__FILE__), __LINE__, ##args);}while(0)
#define INFO(format, args...)   do{printf("\033[1;35m[TEST][%s-%d]\033[m" format, basename(__FILE__), __LINE__, ##args);}while(0)
#define SYSERR(format, args...) do{printf("\033[1;31m[TEST][%s-%d](%s) \033[m" format, basename(__FILE__), __LINE__, strerror(errno), ##args);}while(0)

typedef struct NPU_IMAGE_ST
{
    uint64_t  au64PhyAddr[3]; /* RW;The physical address of the image */
    uint64_t  au64VirAddr[3]; /* RW;The virtual address of the image */
    uint32_t  au32Stride[3];  /* RW;The stride of the image */  
    uint32_t  u32Width;       /* RW;The width of the image */
    uint32_t  u32Height;      /* RW;The height of the image */
    uint32_t  u32AlignHeight;
    uint32_t  u32Size;
    void* reserve;
}NPU_IMAGE_S;

typedef struct MCV_ALGORITHM_RESULT_ST {
    uint64_t frame_id;
    uint32_t object_size;
    uint32_t bind_size;
    uint32_t cache_list_size;
    // the size of the original received image
    uint32_t original_width;
    uint32_t original_height;
    // the size of the algorithm processe image
    uint32_t processed_width;
    uint32_t processed_height;
    // other kind result, data transmission
    uint32_t meta_info_size;
    void *user_data;     // user data
    int reserved[15];    // reserved
} MCV_ALGORITHM_RESULT_S;

typedef struct FRAME_ALGORITHM_RESULT_ST
{
    NPU_IMAGE_S* npu_image;
    MCV_ALGORITHM_RESULT_S* palgorithm_result;
}FRAME_ALGORITHM_RESULT_S;

typedef HASHMAP(char, FRAME_ALGORITHM_RESULT_S) algo_std_map;
typedef struct FRAME_DATA_MAP_ST{
    pthread_mutex_t *map_data_result_lock;
    algo_std_map *map_data_result;
}FRAME_DATA_MAP_S;

static algo_std_map g_mapFaceDataResult;
static pthread_mutex_t g_mapFaceDataResultLock = PTHREAD_MUTEX_INITIALIZER;

static void hashmap_dump(algo_std_map *map, const char *label)
{
    DEBUG("Hashmap stats: %s\n", label);
    DEBUG("    # entries:           %zu\n", hashmap_size(map));
    DEBUG("    Table size:          %zu\n", map->map_base.table_size);
    DEBUG("    Load factor:         %.4f\n", hashmap_load_factor(map));
    DEBUG("    Collisions mean:     %.4f\n", hashmap_collisions_mean(map));
    DEBUG("    Collisions variance: %.4f\n", hashmap_collisions_variance(map));

    const char *key = NULL;
    const char *temp = NULL;
    FRAME_ALGORITHM_RESULT_S *p_frame_algo_result = NULL;
    hashmap_foreach_safe(key, p_frame_algo_result, map, temp)
    {
        if (hashmap_get(map, key) != p_frame_algo_result)
        {
            ERROR("invalid iterator, key is %s.\n", key);
            continue;
        }
        DEBUG("dump key is %s\n", key);
    }
}


static void* send_data_thread(void *lparam)
{
    uint64_t frame_id = 0;

    while (1)
    {
        NPU_IMAGE_S *npu_image = NULL;
        npu_image = (NPU_IMAGE_S *)calloc(1, sizeof(NPU_IMAGE_S));
        if (NULL == npu_image)
        {
            SYSERR("Fail to calloc npu_image.\n");
            usleep(100*1000);
            continue;
        }
        npu_image->u32Width  = frame_id * 10;
        npu_image->u32Height = frame_id * 5;

        int hashmap_ret = -1;
        char key_str[32] = {0};
        FRAME_ALGORITHM_RESULT_S *pstAlgorithmResult = NULL;
        pstAlgorithmResult = (FRAME_ALGORITHM_RESULT_S *)calloc(1, sizeof(FRAME_ALGORITHM_RESULT_S));
        if (pstAlgorithmResult)
        {
            pthread_mutex_lock(&g_mapFaceDataResultLock);
            pstAlgorithmResult->npu_image = npu_image;
            pstAlgorithmResult->palgorithm_result = NULL;
            snprintf(key_str, sizeof(key_str), "%llu", frame_id++);
            hashmap_ret = hashmap_put(&g_mapFaceDataResult, key_str, (void*)pstAlgorithmResult);
            if (hashmap_ret < 0)
            {
                ERROR("Fail to called hashmap_put, key is %s, because of %s.\n", key_str, strerror(-hashmap_ret));
                free(npu_image);
                free(pstAlgorithmResult);
            }
            else
            {
                DEBUG("input: key:%s - pstAlgorithmResult:%p, npu_image:%p, map size %d.\n", 
                       key_str, pstAlgorithmResult, pstAlgorithmResult->npu_image, hashmap_size(&g_mapFaceDataResult));
            }
            pthread_mutex_unlock(&g_mapFaceDataResultLock);
        }
        usleep(100*1000);
    }


    return NULL;
}

static void* recv_data_thread(void *lparam)
{
    while (1)
    {
        pthread_mutex_lock(&g_mapFaceDataResultLock);
        const void *temp = NULL;
        const char *key = NULL;
        void *data = NULL;
        FRAME_ALGORITHM_RESULT_S *pframe_algorithm_result = NULL;
        INFO("hashmap_size is %d.\n", hashmap_size(&g_mapFaceDataResult));
        hashmap_foreach_safe(key, pframe_algorithm_result, &g_mapFaceDataResult, temp)
        {
            data = NULL;
            data = hashmap_get(&g_mapFaceDataResult, key);
            if (data != pframe_algorithm_result)
            {
                ERROR("invalid iterator, data = %p, pframe_algorithm_result=%p.\n",
                      data, pframe_algorithm_result);
                continue;
            }
            printf("--------------------------------------------------------");
            hashmap_dump(&g_mapFaceDataResult, __FUNCTION__);
            DEBUG("found it, key is %s.\n", key);
            printf("--------------------------------------------------------");
        }
        
        pthread_mutex_unlock(&g_mapFaceDataResultLock);
        usleep(500*1000);
    }

    return NULL;
}

int main(int argc, const char *argv[])
{
    pthread_t send_pid = -1;
    pthread_t recv_pid = -1;

    hashmap_init(&g_mapFaceDataResult, hashmap_hash_string, strcmp);

    pthread_create(&send_pid, NULL, send_data_thread, NULL);
    pthread_create(&recv_pid, NULL, recv_data_thread, NULL);

    while(1);

    return 0;
}

Hi @fancong5201314,

The hashmap does not allocate storage for keys by default. Since your key is stored on the stack char key_str[32] = {0};, it is invalidated as soon as you go out of scope of the while loop body. You have a couple choices to fix this:

  1. since your key is a numeric frame ID, change your key type to uint64_t and pass in a pointer to the frame_id already stored in MCV_ALGORITHM_RESULT_ST. This will eliminate the need to do additional memory allocation for keys.
  2. Alternatively, set a key allocator and allow the hashmap to manage memory for key strings. E.g. hashmap_set_key_alloc_funcs(map, strdup, free).

On a different topic, is there any reason FRAME_ALGORITHM_RESULT_ST has a pointer to NPU_IMAGE_ST and MCV_ALGORITHM_RESULT_ST, instead of just containing those structures? If possible, I would do that as it could improve performance by requiring fewer mallocs and reducing memory fragmentation.