MST

星途 面试题库

面试题:C++ 控制结构与多线程编程的交互

在多线程编程环境下,C++ 的控制结构(如条件语句和循环语句)可能会带来一些同步和竞争条件问题。请详细阐述在多线程环境中使用 if - else、for 循环等控制结构时可能遇到的问题,例如数据竞争、死锁等,并说明如何通过使用 mutex、condition_variable 等同步机制来解决这些问题。给出一个多线程程序示例,其中包含控制结构,展示如何正确处理同步问题以确保程序的正确性和稳定性。
41.0万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

在多线程环境中使用控制结构可能遇到的问题

  1. 数据竞争
    • 解释:不同线程同时访问和修改共享数据时,如果没有适当的同步机制,可能会导致数据不一致。例如,在 if - else 语句中,一个线程可能在判断条件后,还未执行相应操作时,另一个线程修改了共享数据,导致第一个线程执行的操作基于过时的数据。在 for 循环中,若循环变量是共享的,多个线程同时对其进行读写操作,也会产生数据竞争。
    • 示例:假设有两个线程对一个共享变量 count 进行操作,一个线程在 if (count > 0) 判断后,还未执行 count-- 时,另一个线程将 count 减为 0,就会出现逻辑错误。
  2. 死锁
    • 解释:当两个或多个线程相互等待对方释放锁时,就会发生死锁。例如,线程 A 持有锁 mutexA 并尝试获取锁 mutexB,而线程 B 持有锁 mutexB 并尝试获取锁 mutexA,双方都不会释放已持有的锁,从而陷入死锁。在使用 for 循环进行复杂资源获取时,如果获取顺序不一致,很容易出现死锁情况。

使用同步机制解决问题

  1. mutex(互斥锁)
    • 作用:用于保护共享资源,确保同一时间只有一个线程可以访问共享资源。
    • 使用方法:在访问共享资源前,线程需要先获取 mutex,访问完后释放 mutex。例如在 if - elsefor 循环中涉及共享资源操作时,在进入相关代码块前加锁,离开时解锁。
  2. condition_variable(条件变量)
    • 作用:用于线程间的同步,一个线程可以等待某个条件满足,而另一个线程在条件满足时通知等待的线程。常用于在 while 循环中,线程等待某个条件发生变化后再继续执行。
    • 使用方法:通常与 mutex 配合使用。一个线程在 while 循环中使用 condition_variablewait 方法等待条件,另一个线程在条件满足时调用 condition_variablenotify_onenotify_all 方法通知等待的线程。

多线程程序示例

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> dataQueue;
bool finished = false;

void producer(int id) {
    for (int i = 0; i < 5; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        dataQueue.push(i * id);
        std::cout << "Producer " << id << " produced: " << i * id << std::endl;
        lock.unlock();
        cv.notify_one();
    }
    std::unique_lock<std::mutex> lock(mtx);
    finished = true;
    cv.notify_all();
}

void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return!dataQueue.empty() || finished; });
        if (dataQueue.empty() && finished) {
            break;
        }
        int data = dataQueue.front();
        dataQueue.pop();
        std::cout << "Consumer consumed: " << data << std::endl;
    }
}

int main() {
    std::thread producer1(producer, 1);
    std::thread producer2(producer, 2);
    std::thread consumerThread(consumer);

    producer1.join();
    producer2.join();
    consumerThread.join();

    return 0;
}

在这个示例中,producer 线程生产数据并放入共享队列 dataQueue 中,consumer 线程从队列中取出数据。mutex 用于保护共享队列,condition_variable 用于线程间的同步,确保消费者线程在队列有数据或生产结束时才进行消费操作,避免了数据竞争和死锁等问题。