MST

星途 面试题库

面试题:C语言中Linux互斥锁死锁场景分析与解决

描述一个在多线程环境下,使用C语言结合Linux互斥锁可能出现死锁的场景,并说明如何避免这种死锁情况,给出代码示例及分析。
22.6万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能出现死锁的场景

在多线程环境下,当多个线程以不同顺序获取多个互斥锁时,就可能出现死锁。例如,线程A获取互斥锁1,然后尝试获取互斥锁2;而线程B获取互斥锁2,然后尝试获取互斥锁1。如果这两个操作同时进行,就会导致死锁。

代码示例

#include <pthread.h>
#include <stdio.h>

// 定义两个互斥锁
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;

void* thread_function1(void* arg) {
    // 线程1获取mutex1
    pthread_mutex_lock(&mutex1);
    printf("Thread 1 has locked mutex1\n");

    // 线程1尝试获取mutex2
    pthread_mutex_lock(&mutex2);
    printf("Thread 1 has locked mutex2\n");

    // 解锁操作(这里不会执行到,因为死锁了)
    pthread_mutex_unlock(&mutex2);
    pthread_mutex_unlock(&mutex1);

    return NULL;
}

void* thread_function2(void* arg) {
    // 线程2获取mutex2
    pthread_mutex_lock(&mutex2);
    printf("Thread 2 has locked mutex2\n");

    // 线程2尝试获取mutex1
    pthread_mutex_lock(&mutex1);
    printf("Thread 2 has locked mutex1\n");

    // 解锁操作(这里不会执行到,因为死锁了)
    pthread_mutex_unlock(&mutex1);
    pthread_mutex_unlock(&mutex2);

    return NULL;
}

分析

在上述代码中,thread_function1先获取mutex1,再获取mutex2;而thread_function2先获取mutex2,再获取mutex1。如果这两个线程同时运行,就可能出现线程1持有mutex1,线程2持有mutex2,然后双方都在等待对方持有的锁,从而导致死锁。

避免死锁的方法

  1. 按顺序获取锁:所有线程都按照相同的顺序获取互斥锁。
  2. 使用超时机制:在获取锁时设置一个超时时间,如果在规定时间内没有获取到锁,则放弃并释放已获取的锁。

按顺序获取锁的代码示例

#include <pthread.h>
#include <stdio.h>

// 定义两个互斥锁
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;

void* thread_function1(void* arg) {
    // 线程1按顺序获取mutex1和mutex2
    pthread_mutex_lock(&mutex1);
    printf("Thread 1 has locked mutex1\n");

    pthread_mutex_lock(&mutex2);
    printf("Thread 1 has locked mutex2\n");

    // 解锁操作
    pthread_mutex_unlock(&mutex2);
    pthread_mutex_unlock(&mutex1);

    return NULL;
}

void* thread_function2(void* arg) {
    // 线程2也按顺序获取mutex1和mutex2
    pthread_mutex_lock(&mutex1);
    printf("Thread 2 has locked mutex1\n");

    pthread_mutex_lock(&mutex2);
    printf("Thread 2 has locked mutex2\n");

    // 解锁操作
    pthread_mutex_unlock(&mutex2);
    pthread_mutex_unlock(&mutex1);

    return NULL;
}

分析

在这个改进的代码中,thread_function1thread_function2都按照先获取mutex1,再获取mutex2的顺序进行操作。这样就避免了死锁的发生,因为不会出现一个线程持有mutex2等待mutex1,而另一个线程持有mutex1等待mutex2的情况。