面试题答案
一键面试多线程下使用 malloc
为结构体动态分配内存可能出现的问题
- 竞态条件:多个线程同时调用
malloc
为结构体分配内存,可能导致结构体的部分成员被不同线程同时修改,从而出现数据不一致的情况。例如,一个线程刚分配好内存并开始给text
赋值,另一个线程可能同时在给value
赋值,这可能导致赋值操作相互干扰。 - 内存泄漏:如果在释放内存时没有正确同步,一个线程可能在另一个线程仍在使用该内存时释放了它,导致悬空指针。另外,如果在分配内存失败时没有正确处理,也可能导致已分配的部分内存无法释放,造成内存泄漏。
确保内存操作线程安全性的方案
-
关键技术点:
- 使用互斥锁(
mutex
)来保护对结构体的所有操作,确保同一时间只有一个线程可以对结构体进行分配、赋值和释放操作。 - 在分配内存时,要检查分配是否成功,避免因分配失败而导致内存泄漏。
- 在释放内存时,要确保没有其他线程正在使用该内存,避免悬空指针。
- 使用互斥锁(
-
代码示例(以 C 语言为例,使用 POSIX 线程库
pthread
):
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 定义共享结构体
struct Shared {
int value;
char *text;
};
// 定义互斥锁
pthread_mutex_t mutex;
// 线程函数,模拟对共享结构体的操作
void* thread_function(void* arg) {
struct Shared *shared = (struct Shared *)arg;
// 加锁
pthread_mutex_lock(&mutex);
// 分配内存
shared->text = (char *)malloc(100);
if (shared->text == NULL) {
// 分配失败处理
perror("malloc");
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
// 赋值
shared->value = 42;
snprintf(shared->text, 100, "Hello, from thread %ld", pthread_self());
// 使用共享结构体数据
printf("Thread %ld: value = %d, text = %s\n", pthread_self(), shared->value, shared->text);
// 释放内存
free(shared->text);
shared->text = NULL;
// 解锁
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main() {
// 初始化互斥锁
pthread_mutex_init(&mutex, NULL);
struct Shared shared;
// 创建多个线程
pthread_t threads[3];
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, thread_function, &shared);
}
// 等待所有线程结束
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
在上述代码中:
- 定义了一个互斥锁
mutex
,并在main
函数中初始化它。 - 在
thread_function
函数中,每次对共享结构体shared
进行操作前先加锁(pthread_mutex_lock
),操作完成后解锁(pthread_mutex_unlock
),这样就避免了竞态条件。 - 在分配内存后检查是否成功,失败时进行相应处理并释放已分配的资源(如果有的话),防止内存泄漏。
- 在释放内存后将指针置为
NULL
,避免悬空指针。最后在main
函数结束时销毁互斥锁。