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:
- since your key is a numeric frame ID, change your key type to
uint64_t
and pass in a pointer to theframe_id
already stored inMCV_ALGORITHM_RESULT_ST
. This will eliminate the need to do additional memory allocation for keys. - 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.