MST

星途 面试题库

面试题:C语言中Linux条件变量广播的线程安全问题

在多线程环境下,使用C语言基于Linux条件变量广播机制时,可能会出现哪些线程安全问题?如何避免这些问题?请结合具体场景进行分析,并给出代码示例说明解决方案。
29.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能出现的线程安全问题

  1. 虚假唤醒:在多线程环境中,条件变量的等待函数可能会在没有收到真实的条件通知时就被唤醒,这可能导致线程执行不必要的操作。
  2. 竞态条件:多个线程同时访问和修改共享资源,如果没有正确的同步机制,可能导致数据不一致。例如,一个线程在检查条件并等待条件变量时,另一个线程可能在这个间隙修改了共享资源,导致第一个线程错过条件变化。

避免问题的方法

  1. 处理虚假唤醒:在条件变量的等待循环中,使用while循环而不是if语句来检查条件,确保每次唤醒后再次检查条件是否真的满足。
  2. 解决竞态条件:使用互斥锁来保护共享资源,在访问共享资源前加锁,访问结束后解锁。

具体场景分析与代码示例

假设我们有一个生产者 - 消费者模型,生产者线程生产数据,消费者线程消费数据。共享资源是一个缓冲区,当缓冲区为空时,消费者线程等待;当缓冲区满时,生产者线程等待。

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

#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
int count = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t not_empty = PTHREAD_COND_INITIALIZER;
pthread_cond_t not_full = PTHREAD_COND_INITIALIZER;

void *producer(void *arg) {
    int i;
    for (i = 0; i < 10; i++) {
        pthread_mutex_lock(&mutex);
        while (count == BUFFER_SIZE) {
            pthread_cond_wait(&not_full, &mutex);
        }
        buffer[in] = i;
        printf("Produced: %d\n", buffer[in]);
        in = (in + 1) % BUFFER_SIZE;
        count++;
        pthread_cond_signal(&not_empty);
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    return NULL;
}

void *consumer(void *arg) {
    int i;
    for (i = 0; i < 10; i++) {
        pthread_mutex_lock(&mutex);
        while (count == 0) {
            pthread_cond_wait(&not_empty, &mutex);
        }
        int data = buffer[out];
        printf("Consumed: %d\n", data);
        out = (out + 1) % BUFFER_SIZE;
        count--;
        pthread_cond_signal(&not_full);
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    return NULL;
}

int main() {
    pthread_t producer_thread, consumer_thread;
    pthread_create(&producer_thread, NULL, producer, NULL);
    pthread_create(&consumer_thread, NULL, consumer, NULL);

    pthread_join(producer_thread, NULL);
    pthread_join(consumer_thread, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&not_empty);
    pthread_cond_destroy(&not_full);

    return 0;
}

在这个示例中:

  1. 使用pthread_mutex_t类型的互斥锁mutex来保护共享资源bufferinoutcount,避免竞态条件。
  2. 使用pthread_cond_t类型的条件变量not_emptynot_full来通知缓冲区状态的变化。
  3. pthread_cond_wait的循环中使用while检查条件,避免虚假唤醒。这样可以确保线程在真正满足条件时才执行相应操作,保证了多线程环境下的线程安全。