MST

星途 面试题库

面试题:C++嵌套类在多线程环境下的作用域与生命周期挑战

在多线程环境中,有一个外层类ThreadSafeOuter,其内部嵌套了类InnerResource。InnerResource管理着一些共享资源。当多个线程同时访问ThreadSafeOuter对象,并可能创建或销毁InnerResource对象时,如何保证InnerResource的作用域和生命周期在多线程竞争条件下的正确性,避免数据竞争和未定义行为?请从线程同步机制、内存模型等方面详细阐述,并给出相应的代码示例。
17.5万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

1. 线程同步机制

  • 互斥锁(Mutex)
    • 使用互斥锁来保护对 InnerResource 的创建和销毁操作。当一个线程要创建或销毁 InnerResource 时,先获取互斥锁,操作完成后释放互斥锁。这样可以保证同一时间只有一个线程能对 InnerResource 进行创建或销毁操作,避免数据竞争。
    • 在C++ 中,可以使用 std::mutex 来实现。例如:
#include <iostream>
#include <mutex>
#include <thread>

class InnerResource {
public:
    InnerResource() { std::cout << "InnerResource created" << std::endl; }
    ~InnerResource() { std::cout << "InnerResource destroyed" << std::endl; }
};

class ThreadSafeOuter {
private:
    InnerResource* innerResource;
    std::mutex innerMutex;
public:
    ThreadSafeOuter() : innerResource(nullptr) {}
    ~ThreadSafeOuter() {
        std::lock_guard<std::mutex> lock(innerMutex);
        if (innerResource) {
            delete innerResource;
        }
    }
    InnerResource* getInnerResource() {
        std::lock_guard<std::mutex> lock(innerMutex);
        if (!innerResource) {
            innerResource = new InnerResource();
        }
        return innerResource;
    }
};

void threadFunction(ThreadSafeOuter& outer) {
    InnerResource* resource = outer.getInnerResource();
    // 使用 resource 进行操作
}

int main() {
    ThreadSafeOuter outer;
    std::thread t1(threadFunction, std::ref(outer));
    std::thread t2(threadFunction, std::ref(outer));
    t1.join();
    t2.join();
    return 0;
}
  • 读写锁(Read - Write Lock)
    • 如果对 InnerResource 的操作主要是读多写少,可以使用读写锁。多个线程可以同时读取 InnerResource,但在写入(创建或销毁)时需要独占锁。在C++ 中,可以使用 std::shared_mutex 来实现。例如:
#include <iostream>
#include <shared_mutex>
#include <thread>

class InnerResource {
public:
    InnerResource() { std::cout << "InnerResource created" << std::endl; }
    ~InnerResource() { std::cout << "InnerResource destroyed" << std::endl; }
};

class ThreadSafeOuter {
private:
    InnerResource* innerResource;
    std::shared_mutex innerMutex;
public:
    ThreadSafeOuter() : innerResource(nullptr) {}
    ~ThreadSafeOuter() {
        std::unique_lock<std::shared_mutex> lock(innerMutex);
        if (innerResource) {
            delete innerResource;
        }
    }
    InnerResource* getInnerResource() {
        std::shared_lock<std::shared_mutex> lock(innerMutex);
        if (!innerResource) {
            lock.unlock();
            std::unique_lock<std::shared_mutex> exclusiveLock(innerMutex);
            if (!innerResource) {
                innerResource = new InnerResource();
            }
        }
        return innerResource;
    }
};

void threadFunction(ThreadSafeOuter& outer) {
    InnerResource* resource = outer.getInnerResource();
    // 使用 resource 进行操作
}

int main() {
    ThreadSafeOuter outer;
    std::thread t1(threadFunction, std::ref(outer));
    std::thread t2(threadFunction, std::ref(outer));
    t1.join();
    t2.join();
    return 0;
}

2. 内存模型

  • 顺序一致性(Sequential Consistency)
    • 确保所有线程以相同的顺序看到对 InnerResource 的创建和销毁操作。在C++ 中,使用 std::memory_order_seq_cst 内存序可以达到顺序一致性。例如,在 std::atomic 类型变量的操作中使用该内存序。但在上述示例中,由于使用了 std::mutexstd::mutex 已经提供了足够的内存同步保证,使得对 InnerResource 的操作在不同线程间具有顺序一致性。
    • 例如,对于 InnerResource* 指针的更新,可以使用 std::atomic<InnerResource*> 并结合 std::memory_order_seq_cst 内存序来保证顺序一致性:
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>

class InnerResource {
public:
    InnerResource() { std::cout << "InnerResource created" << std::endl; }
    ~InnerResource() { std::cout << "InnerResource destroyed" << std::endl; }
};

class ThreadSafeOuter {
private:
    std::atomic<InnerResource*> innerResource;
    std::mutex innerMutex;
public:
    ThreadSafeOuter() : innerResource(nullptr) {}
    ~ThreadSafeOuter() {
        std::lock_guard<std::mutex> lock(innerMutex);
        InnerResource* res = innerResource.load(std::memory_order_seq_cst);
        if (res) {
            delete res;
        }
    }
    InnerResource* getInnerResource() {
        InnerResource* res = innerResource.load(std::memory_order_acquire);
        if (!res) {
            std::lock_guard<std::mutex> lock(innerMutex);
            res = innerResource.load(std::memory_order_relaxed);
            if (!res) {
                InnerResource* newRes = new InnerResource();
                innerResource.store(newRes, std::memory_order_release);
                res = newRes;
            }
        }
        return res;
    }
};

void threadFunction(ThreadSafeOuter& outer) {
    InnerResource* resource = outer.getInnerResource();
    // 使用 resource 进行操作
}

int main() {
    ThreadSafeOuter outer;
    std::thread t1(threadFunction, std::ref(outer));
    std::thread t2(threadFunction, std::ref(outer));
    t1.join();
    t2.join();
    return 0;
}

通过上述线程同步机制(互斥锁、读写锁等)和内存模型(顺序一致性等)的结合使用,可以保证 InnerResource 的作用域和生命周期在多线程竞争条件下的正确性,避免数据竞争和未定义行为。