MST

星途 面试题库

面试题:C语言NULL指针在多线程编程中的挑战与应对策略

在C语言的多线程编程环境下,NULL指针会带来哪些独特的挑战?例如线程安全问题、竞争条件等。请结合pthread库,详细说明如何设计代码以有效应对这些挑战,确保NULL指针在多线程场景下的正确使用。
32.2万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

NULL指针在C语言多线程编程中的挑战

  1. 线程安全问题:多个线程可能同时访问一个指向NULL的指针,导致未定义行为。例如,一个线程可能检查指针是否为NULL,然后在另一个线程将其设为NULL后,第一个线程尝试解引用该指针,从而引发程序崩溃。
  2. 竞争条件:当一个线程释放一个指针所指向的内存,并将指针设为NULL,而另一个线程正在检查该指针是否为NULL时,可能会出现竞争条件。如果第二个线程在第一个线程将指针设为NULL之前检查,就可能访问到已释放的内存。

结合pthread库应对挑战的代码设计

  1. 使用互斥锁
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    int *ptr = NULL;
    
    void* thread_function(void* arg) {
        pthread_mutex_lock(&mutex);
        if (ptr == NULL) {
            ptr = (int*)malloc(sizeof(int));
            if (ptr == NULL) {
                perror("malloc");
                pthread_mutex_unlock(&mutex);
                pthread_exit(NULL);
            }
            *ptr = 42;
        }
        printf("Thread: Value of ptr: %d\n", *ptr);
        pthread_mutex_unlock(&mutex);
        pthread_exit(NULL);
    }
    
    int main() {
        pthread_t thread;
        if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
            perror("pthread_create");
            return 1;
        }
        if (pthread_join(thread, NULL) != 0) {
            perror("pthread_join");
            return 1;
        }
        pthread_mutex_destroy(&mutex);
        if (ptr != NULL) {
            free(ptr);
        }
        return 0;
    }
    
    • 在这段代码中,互斥锁 mutex 用于保护对 ptr 的访问。在检查 ptr 是否为NULL以及分配内存的过程中,通过 pthread_mutex_lockpthread_mutex_unlock 来确保同一时间只有一个线程能操作 ptr
  2. 双重检查锁定
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    int *ptr = NULL;
    
    void* thread_function(void* arg) {
        if (ptr == NULL) {
            pthread_mutex_lock(&mutex);
            if (ptr == NULL) {
                ptr = (int*)malloc(sizeof(int));
                if (ptr == NULL) {
                    perror("malloc");
                    pthread_mutex_unlock(&mutex);
                    pthread_exit(NULL);
                }
                *ptr = 42;
            }
            pthread_mutex_unlock(&mutex);
        }
        printf("Thread: Value of ptr: %d\n", *ptr);
        pthread_exit(NULL);
    }
    
    int main() {
        pthread_t thread;
        if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
            perror("pthread_create");
            return 1;
        }
        if (pthread_join(thread, NULL) != 0) {
            perror("pthread_join");
            return 1;
        }
        pthread_mutex_destroy(&mutex);
        if (ptr != NULL) {
            free(ptr);
        }
        return 0;
    }
    
    • 双重检查锁定机制在访问共享资源前,先进行一次快速的非锁定检查,然后再锁定互斥锁进行更详细的检查。这样可以减少不必要的锁竞争,提高性能。但要注意,在一些编译器优化的情况下,可能需要使用内存屏障来确保正确性。
  3. 使用读写锁
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
    int *ptr = NULL;
    
    void* read_thread_function(void* arg) {
        pthread_rwlock_rdlock(&rwlock);
        if (ptr != NULL) {
            printf("Read Thread: Value of ptr: %d\n", *ptr);
        } else {
            printf("Read Thread: ptr is NULL\n");
        }
        pthread_rwlock_unlock(&rwlock);
        pthread_exit(NULL);
    }
    
    void* write_thread_function(void* arg) {
        pthread_rwlock_wrlock(&rwlock);
        if (ptr == NULL) {
            ptr = (int*)malloc(sizeof(int));
            if (ptr == NULL) {
                perror("malloc");
                pthread_rwlock_unlock(&rwlock);
                pthread_exit(NULL);
            }
            *ptr = 42;
        }
        pthread_rwlock_unlock(&rwlock);
        pthread_exit(NULL);
    }
    
    int main() {
        pthread_t read_thread, write_thread;
        if (pthread_create(&read_thread, NULL, read_thread_function, NULL) != 0) {
            perror("pthread_create");
            return 1;
        }
        if (pthread_create(&write_thread, NULL, write_thread_function, NULL) != 0) {
            perror("pthread_create");
            return 1;
        }
        if (pthread_join(read_thread, NULL) != 0) {
            perror("pthread_join");
            return 1;
        }
        if (pthread_join(write_thread, NULL) != 0) {
            perror("pthread_join");
            return 1;
        }
        pthread_rwlock_destroy(&rwlock);
        if (ptr != NULL) {
            free(ptr);
        }
        return 0;
    }
    
    • 读写锁 pthread_rwlock 允许在多线程环境中区分读操作和写操作。读操作可以并发执行,而写操作需要独占访问。这在读取操作频繁而写入操作较少的场景下能提高性能,同时保证对 ptr 的安全访问。