面试题答案
一键面试性能瓶颈和资源管理问题
- 性能瓶颈
- 线程创建开销:线程创建涉及内核态与用户态的切换,需要分配内核资源,如线程控制块(TCB)等,频繁创建线程会导致系统开销增大。
- 线程终止开销:线程终止同样需要内核处理,释放相关资源,频繁终止也会带来额外开销。
- 调度开销:大量线程竞争CPU资源,增加了调度器的工作负担,导致CPU在上下文切换上花费更多时间,降低了实际执行任务的时间占比。
- 资源管理问题
- 文件描述符泄漏:如果在线程中打开了文件描述符,但在线程终止时没有正确关闭,会导致文件描述符泄漏,最终耗尽系统资源。
- 内存泄漏:线程中动态分配的内存,如果在线程终止时没有释放,会造成内存泄漏。
- 锁争用:多个线程可能竞争同一资源,使用锁进行同步时,如果设计不当,会出现锁争用问题,降低系统并发性能。
优化措施
- 优化线程创建与终止机制
- 线程池:提前创建一定数量的线程并放入线程池,任务来时直接从线程池获取线程执行,任务完成后线程不终止而是返回线程池等待下一个任务。这样减少了线程创建和终止的开销。
- 延迟线程终止:对于一些需要频繁创建和终止的线程,可以采用延迟终止策略,即线程执行完任务后不立即终止,而是等待一段时间,看是否有新任务到来,避免反复创建和销毁。
- 资源分配策略
- 资源预分配:在线程池创建时,预先分配一些常用资源,如文件描述符、内存等,线程从线程池获取资源,使用完后归还,减少资源动态分配和释放的开销。
- 资源复用:对于一些可复用的资源,如数据库连接等,在线程间共享使用,避免每个线程都创建新的资源。
代码示例
以下是一个简单的线程池示例代码,使用C语言和POSIX线程库:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define THREAD_POOL_SIZE 5
#define TASK_QUEUE_SIZE 10
// 任务结构体
typedef struct Task {
void (*func)(void*);
void *arg;
struct Task *next;
} Task;
// 线程池结构体
typedef struct ThreadPool {
pthread_t threads[THREAD_POOL_SIZE];
Task *task_queue_head;
Task *task_queue_tail;
int task_queue_count;
pthread_mutex_t queue_mutex;
pthread_cond_t queue_cond;
int stop;
} ThreadPool;
// 初始化线程池
void initThreadPool(ThreadPool *pool) {
pool->task_queue_head = NULL;
pool->task_queue_tail = NULL;
pool->task_queue_count = 0;
pool->stop = 0;
pthread_mutex_init(&pool->queue_mutex, NULL);
pthread_cond_init(&pool->queue_cond, NULL);
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_create(&pool->threads[i], NULL, (void* (*)(void*))[](void* arg) {
ThreadPool *pool = (ThreadPool *)arg;
while (1) {
Task *task = NULL;
pthread_mutex_lock(&pool->queue_mutex);
while (pool->task_queue_count == 0 &&!pool->stop) {
pthread_cond_wait(&pool->queue_cond, &pool->queue_mutex);
}
if (pool->stop && pool->task_queue_count == 0) {
pthread_mutex_unlock(&pool->queue_mutex);
pthread_exit(NULL);
}
task = pool->task_queue_head;
pool->task_queue_head = task->next;
if (pool->task_queue_head == NULL) {
pool->task_queue_tail = NULL;
}
pool->task_queue_count--;
pthread_mutex_unlock(&pool->queue_mutex);
(*task->func)(task->arg);
free(task);
}
}, pool);
}
}
// 添加任务到线程池
void addTask(ThreadPool *pool, void (*func)(void*), void *arg) {
Task *task = (Task *)malloc(sizeof(Task));
task->func = func;
task->arg = arg;
task->next = NULL;
pthread_mutex_lock(&pool->queue_mutex);
if (pool->task_queue_tail == NULL) {
pool->task_queue_head = task;
pool->task_queue_tail = task;
} else {
pool->task_queue_tail->next = task;
pool->task_queue_tail = task;
}
pool->task_queue_count++;
pthread_cond_signal(&pool->queue_cond);
pthread_mutex_unlock(&pool->queue_mutex);
}
// 销毁线程池
void destroyThreadPool(ThreadPool *pool) {
pthread_mutex_lock(&pool->queue_mutex);
pool->stop = 1;
pthread_cond_broadcast(&pool->queue_cond);
pthread_mutex_unlock(&pool->queue_mutex);
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_join(pool->threads[i], NULL);
}
pthread_mutex_destroy(&pool->queue_mutex);
pthread_cond_destroy(&pool->queue_cond);
}
// 示例任务函数
void exampleTask(void *arg) {
printf("Task executed with argument: %d\n", *((int *)arg));
sleep(1);
}
int main() {
ThreadPool pool;
initThreadPool(&pool);
int args[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
addTask(&pool, exampleTask, &args[i]);
}
sleep(3);
destroyThreadPool(&pool);
return 0;
}
在这个示例中,通过线程池机制,减少了线程创建和终止的开销,同时通过合理的资源管理(如任务结构体的动态分配和释放),避免了内存泄漏等问题。