MST

星途 面试题库

面试题:C语言多线程服务器中定时器与线程同步问题

在一个使用C语言开发的多线程服务器程序里,多个线程可能会访问和修改定时器相关的数据。请描述可能出现的线程同步问题,并阐述如何使用互斥锁(`pthread_mutex_t`)、条件变量(`pthread_cond_t`)来解决这些问题,给出具体的代码实现思路和关键代码片段。
37.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

可能出现的线程同步问题

  1. 数据竞争:多个线程同时访问和修改定时器相关数据,可能导致数据不一致。例如,一个线程在更新定时器的时间,另一个线程同时读取该定时器时间,可能读到未完全更新的数据。
  2. 竞态条件:由于线程执行顺序的不确定性,可能会导致程序出现非预期的行为。比如,一个线程检查定时器是否到期,然后准备执行相关任务,但在检查和执行任务之间,另一个线程修改了定时器状态,导致错误执行。

使用互斥锁和条件变量解决问题的思路

  1. 互斥锁(pthread_mutex_t:用于保护共享数据,确保同一时间只有一个线程可以访问和修改定时器数据。在访问和修改定时器数据前,线程必须先获取互斥锁,操作完成后释放互斥锁。
  2. 条件变量(pthread_cond_t:用于线程间的同步,当定时器满足某个条件(如到期)时,通知等待在条件变量上的线程。一个线程在等待定时器满足条件时,会释放互斥锁并阻塞在条件变量上,当条件满足时,由其他线程唤醒该线程,该线程重新获取互斥锁后继续执行。

关键代码片段

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

// 定义定时器数据结构
typedef struct {
    int time;
    int is_expired;
} Timer;

Timer timer;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 模拟定时器更新线程
void* update_timer(void* arg) {
    while (1) {
        pthread_mutex_lock(&mutex);
        // 更新定时器数据
        timer.time--;
        if (timer.time <= 0) {
            timer.is_expired = 1;
            // 定时器到期,通知等待的线程
            pthread_cond_signal(&cond);
        }
        pthread_mutex_unlock(&mutex);
        // 模拟其他操作
        sleep(1);
    }
    return NULL;
}

// 模拟定时器检查线程
void* check_timer(void* arg) {
    while (1) {
        pthread_mutex_lock(&mutex);
        // 等待定时器到期
        while (!timer.is_expired) {
            pthread_cond_wait(&cond, &mutex);
        }
        // 定时器到期,执行相关任务
        printf("Timer expired, do something.\n");
        timer.is_expired = 0;
        pthread_mutex_unlock(&mutex);
        // 模拟其他操作
        sleep(1);
    }
    return NULL;
}

int main() {
    timer.time = 5;
    timer.is_expired = 0;

    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, update_timer, NULL);
    pthread_create(&tid2, NULL, check_timer, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    return 0;
}

在上述代码中:

  • update_timer 函数模拟定时器更新线程,每次更新定时器数据时先获取互斥锁,更新完成后释放互斥锁。当定时器到期时,发送条件变量信号。
  • check_timer 函数模拟定时器检查线程,在等待定时器到期时,先获取互斥锁,然后在条件变量上等待,被唤醒后执行相关任务,最后释放互斥锁。
  • main 函数初始化定时器数据、互斥锁和条件变量,创建并启动两个线程,最后等待线程结束并销毁互斥锁和条件变量。