如何使我自己的 malloc 线程安全以及在哪里锁定和解锁?
How to make my own malloc thread safe and where to lock and unlock?
我正在实现自己的内存分配器,但我想解决线程安全问题。这是我的 malloc 实现:
pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER; /*< Mutex for protecting the linked list */
void *malloc(size_t size)
{
pthread_mutex_lock(&alloc_mutex);
size_t total_size = size + sizeof(struct mem_block);
size_t aligned_size = total_size;
if (total_size % 8 !=0) {
aligned_size = (total_size / 8) * 8 + 8;
}
LOG("Allocation: request size = %zu, total size = %zu, aligned size = %zu\n", size, total_size, aligned_size);
struct mem_block *reused_block = reuse(aligned_size);
if(reused_block != NULL){
return reused_block + 1;
}
int page_size = getpagesize();
size_t num_pages = aligned_size / page_size;
if(aligned_size % page_size != 0){
num_pages++;
}
size_t region_size = num_pages * page_size;
struct mem_block *block = mmap(NULL, region_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(block == MAP_FAILED){
perror("mmap");
return NULL;
}
snprintf(block->name, 32, "Allocation %lu", g_allocations++);
block->size = region_size;
block->free = true;
block->region_id = g_regions++;
if(g_head == NULL && g_tail == NULL){
block->next = NULL;
block->prev = NULL;
g_head = block;
g_tail = block;
}
else {
g_tail->next = block;
block->prev = g_tail;
block->next = NULL;
g_tail = block;
}
split_block(block, aligned_size);
block->free = false;
pthread_mutex_unlock(&alloc_mutex);
return block+1;
}
我的主要问题是:为了实现线程安全,我需要在哪里锁定和解锁?因为不是。
您可以实现两个函数,一个称为 'malloc_impl',具有主要功能,另一个称为 'malloc',用于锁定互斥体,调用 'malloc_impl' 并将其解锁。
另一个解决方案是使用 'goto'。视情况跳转到具体的label,这样只需要指定一次解锁即可。
示例:
void *block = NULL;
if (err_cond)
goto fail;
if (cond)
goto done;
// do some other stuff
goto done;
fail:
block = NULL;
done:
unlock_mutex();
return block;
p.s。是的,goto 是邪恶的,但有时非常(非常)有用。
我正在实现自己的内存分配器,但我想解决线程安全问题。这是我的 malloc 实现:
pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER; /*< Mutex for protecting the linked list */
void *malloc(size_t size)
{
pthread_mutex_lock(&alloc_mutex);
size_t total_size = size + sizeof(struct mem_block);
size_t aligned_size = total_size;
if (total_size % 8 !=0) {
aligned_size = (total_size / 8) * 8 + 8;
}
LOG("Allocation: request size = %zu, total size = %zu, aligned size = %zu\n", size, total_size, aligned_size);
struct mem_block *reused_block = reuse(aligned_size);
if(reused_block != NULL){
return reused_block + 1;
}
int page_size = getpagesize();
size_t num_pages = aligned_size / page_size;
if(aligned_size % page_size != 0){
num_pages++;
}
size_t region_size = num_pages * page_size;
struct mem_block *block = mmap(NULL, region_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(block == MAP_FAILED){
perror("mmap");
return NULL;
}
snprintf(block->name, 32, "Allocation %lu", g_allocations++);
block->size = region_size;
block->free = true;
block->region_id = g_regions++;
if(g_head == NULL && g_tail == NULL){
block->next = NULL;
block->prev = NULL;
g_head = block;
g_tail = block;
}
else {
g_tail->next = block;
block->prev = g_tail;
block->next = NULL;
g_tail = block;
}
split_block(block, aligned_size);
block->free = false;
pthread_mutex_unlock(&alloc_mutex);
return block+1;
}
我的主要问题是:为了实现线程安全,我需要在哪里锁定和解锁?因为不是。
您可以实现两个函数,一个称为 'malloc_impl',具有主要功能,另一个称为 'malloc',用于锁定互斥体,调用 'malloc_impl' 并将其解锁。
另一个解决方案是使用 'goto'。视情况跳转到具体的label,这样只需要指定一次解锁即可。
示例:
void *block = NULL;
if (err_cond)
goto fail;
if (cond)
goto done;
// do some other stuff
goto done;
fail:
block = NULL;
done:
unlock_mutex();
return block;
p.s。是的,goto 是邪恶的,但有时非常(非常)有用。