MST
星途 面试题库

面试题:C语言线程局部存储清理在复杂场景中的应用

假设你正在开发一个多线程的网络服务器程序,使用C语言结合Linux的线程局部存储。其中每个线程会分配一些资源(如数据库连接、文件描述符等),当线程结束时需要正确清理这些资源。描述如何设计线程局部存储的清理机制,以确保资源的正确释放,并且避免内存泄漏和其他潜在的错误,同时给出关键代码片段。
48.5万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试
  1. 设计思路
    • 使用Linux的线程局部存储(TLS)机制,通过pthread_key_create创建一个线程局部存储的键。
    • 每个线程在使用资源前,将资源句柄(如数据库连接、文件描述符等)存储到这个线程局部存储键对应的位置。
    • 利用pthread_key_create的第二个参数,设置一个清理函数,当线程退出时,该清理函数会被自动调用,用于释放线程局部存储中保存的资源。
  2. 关键代码片段
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

// 假设这是我们要管理的资源结构体
typedef struct {
    int file_descriptor;
    // 可以在这里添加数据库连接等其他资源
} ThreadResource;

// 线程局部存储键
pthread_key_t resource_key;

// 清理函数,用于释放资源
void resource_cleanup(void* arg) {
    ThreadResource* resource = (ThreadResource*)arg;
    if (resource) {
        // 关闭文件描述符
        if (resource->file_descriptor != -1) {
            close(resource->file_descriptor);
        }
        free(resource);
    }
}

// 线程执行函数
void* thread_function(void* arg) {
    // 分配资源
    ThreadResource* resource = (ThreadResource*)malloc(sizeof(ThreadResource));
    if (!resource) {
        perror("malloc");
        pthread_exit(NULL);
    }
    resource->file_descriptor = open("test.txt", O_RDONLY);
    if (resource->file_descriptor == -1) {
        perror("open");
        free(resource);
        pthread_exit(NULL);
    }

    // 将资源存储到线程局部存储
    pthread_setspecific(resource_key, resource);

    // 线程的其他工作

    pthread_exit(NULL);
}

int main() {
    // 创建线程局部存储键,并设置清理函数
    if (pthread_key_create(&resource_key, resource_cleanup) != 0) {
        perror("pthread_key_create");
        return 1;
    }

    pthread_t thread;
    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
        perror("pthread_create");
        pthread_key_delete(resource_key);
        return 1;
    }

    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        perror("pthread_join");
        pthread_key_delete(resource_key);
        return 1;
    }

    // 删除线程局部存储键
    pthread_key_delete(resource_key);
    return 0;
}

上述代码展示了如何创建线程局部存储键,在每个线程中分配资源并存储到线程局部存储,以及通过清理函数在每个线程结束时正确释放资源,从而避免内存泄漏等问题。