MST

星途 面试题库

面试题:C语言多线程数据共享的死锁问题

在Linux C语言多线程编程中,描述死锁在多线程数据共享场景下是如何产生的,例如有两个线程T1和T2,它们分别需要获取两把锁L1和L2来操作共享数据,怎样的操作顺序可能导致死锁?并且说明如何避免这种死锁情况,给出避免死锁的代码结构示例。
20.7万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

死锁产生原因

在多线程数据共享场景下,死锁产生的原因主要有以下几点:

  1. 互斥条件:每个锁在同一时间只能被一个线程持有。
  2. 占有并等待:线程在持有一个锁的同时,等待获取其他锁。
  3. 不可剥夺:锁不能被强制从持有它的线程中夺走。
  4. 循环等待:线程之间形成一个环形的等待链,每个线程都在等待下一个线程持有的锁。

可能导致死锁的操作顺序

对于两个线程T1和T2,以及两把锁L1和L2,如果按照以下顺序操作可能导致死锁:

  1. 线程T1:获取锁L1。
  2. 线程T2:获取锁L2。
  3. 线程T1:尝试获取锁L2,但此时锁L2被线程T2持有,线程T1进入等待状态。
  4. 线程T2:尝试获取锁L1,但此时锁L1被线程T1持有,线程T2进入等待状态。 这样就形成了循环等待,导致死锁。

避免死锁的方法

  1. 按顺序获取锁:所有线程都按照相同的顺序获取锁,例如都先获取L1,再获取L2。
  2. 超时机制:设置获取锁的超时时间,如果在规定时间内没有获取到锁,则释放已经获取的锁,并进行相应处理。
  3. 资源分配图算法:通过算法检测是否会出现死锁,如果会则不进行资源分配。

避免死锁的代码结构示例(按顺序获取锁)

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

// 定义两把锁
pthread_mutex_t L1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t L2 = PTHREAD_MUTEX_INITIALIZER;

// 线程1的执行函数
void* thread1(void* arg) {
    // 按顺序获取锁
    pthread_mutex_lock(&L1);
    printf("Thread 1 acquired L1\n");
    pthread_mutex_lock(&L2);
    printf("Thread 1 acquired L2\n");
    // 操作共享数据
    // 释放锁
    pthread_mutex_unlock(&L2);
    pthread_mutex_unlock(&L1);
    return NULL;
}

// 线程2的执行函数
void* thread2(void* arg) {
    // 按顺序获取锁
    pthread_mutex_lock(&L1);
    printf("Thread 2 acquired L1\n");
    pthread_mutex_lock(&L2);
    printf("Thread 2 acquired L2\n");
    // 操作共享数据
    // 释放锁
    pthread_mutex_unlock(&L2);
    pthread_mutex_unlock(&L1);
    return NULL;
}

int main() {
    pthread_t t1, t2;

    // 创建线程1
    if (pthread_create(&t1, NULL, thread1, NULL) != 0) {
        printf("\n ERROR creating thread 1");
        return 1;
    }

    // 创建线程2
    if (pthread_create(&t2, NULL, thread2, NULL) != 0) {
        printf("\n ERROR creating thread 2");
        return 1;
    }

    // 等待线程1和线程2结束
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    // 销毁锁
    pthread_mutex_destroy(&L1);
    pthread_mutex_destroy(&L2);

    return 0;
}

在上述代码中,两个线程都按照先获取L1,再获取L2的顺序进行操作,从而避免了死锁的发生。