MST

星途 面试题库

面试题:C++多线程环境下重写拷贝构造函数的性能考量与同步策略

在多线程环境中,重写拷贝构造函数会面临更多的挑战。请分析多线程环境下重写拷贝构造函数可能出现的性能问题,如数据竞争、锁争用等。针对这些问题,提出至少两种有效的同步策略,并详细解释每种策略的原理、适用场景以及对性能的影响。同时,给出相应的多线程代码示例来演示你的解决方案。
25.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

多线程环境下重写拷贝构造函数可能出现的性能问题

  1. 数据竞争:多个线程同时访问和修改共享数据,导致数据不一致。例如,在拷贝构造函数中,如果源对象的数据成员被多个线程同时修改,而拷贝过程尚未完成,就会出现数据竞争。
  2. 锁争用:为了避免数据竞争,通常会使用锁机制。但如果锁的粒度设置不当,多个线程频繁竞争同一把锁,会导致线程阻塞,降低系统的并发性能。

同步策略

  1. 互斥锁(Mutex)
    • 原理:互斥锁是一种二元信号量,它有两种状态:锁定和解锁。当一个线程获取到互斥锁(将其锁定),其他线程就无法获取,直到该线程释放互斥锁(将其解锁)。在拷贝构造函数中,通过在进入函数时加锁,离开函数时解锁,确保同一时间只有一个线程可以执行拷贝操作。
    • 适用场景:适用于对共享资源访问频率较高,且拷贝操作相对简单、耗时较短的场景。
    • 对性能的影响:由于同一时间只有一个线程能执行拷贝构造函数,可能会降低并发性能。尤其是在高并发环境下,如果拷贝操作频繁,锁争用会比较严重,导致线程等待时间增加,整体性能下降。
    • 代码示例
#include <iostream>
#include <mutex>

class MyClass {
private:
    int data;
    static std::mutex mtx;
public:
    MyClass(int value) : data(value) {}
    MyClass(const MyClass& other) {
        std::lock_guard<std::mutex> lock(mtx);
        data = other.data;
    }
    int getData() const {
        return data;
    }
};

std::mutex MyClass::mtx;

void threadFunction() {
    MyClass obj1(10);
    MyClass obj2(obj1);
    std::cout << "Copied data: " << obj2.getData() << std::endl;
}

int main() {
    std::thread t1(threadFunction);
    std::thread t2(threadFunction);

    t1.join();
    t2.join();

    return 0;
}
  1. 读写锁(Read - Write Lock)
    • 原理:读写锁区分了读操作和写操作。允许多个线程同时进行读操作,因为读操作不会修改共享数据,不会产生数据竞争。但写操作时,需要独占锁,以防止其他线程进行读或写操作。在拷贝构造函数中,如果拷贝过程只是读取源对象的数据(不进行修改),可以使用读锁;如果需要修改数据成员(例如引用计数的更新等),则使用写锁。
    • 适用场景:适用于读操作远远多于写操作的场景。在拷贝构造函数中,如果大部分操作是读取源对象数据,使用读写锁可以提高并发性能。
    • 对性能的影响:读操作时,由于允许多个线程并发执行,提高了并发性能。但写操作时,仍然需要独占锁,可能会导致其他线程等待。如果写操作频繁,性能提升可能不明显,甚至会因为锁的切换开销而降低性能。
    • 代码示例
#include <iostream>
#include <shared_mutex>

class MyClass {
private:
    int data;
    static std::shared_mutex rw_mtx;
public:
    MyClass(int value) : data(value) {}
    MyClass(const MyClass& other) {
        std::shared_lock<std::shared_mutex> lock(rw_mtx);
        data = other.data;
    }
    int getData() const {
        std::shared_lock<std::shared_mutex> lock(rw_mtx);
        return data;
    }
    void setData(int value) {
        std::unique_lock<std::shared_mutex> lock(rw_mtx);
        data = value;
    }
};

std::shared_mutex MyClass::rw_mtx;

void readThreadFunction() {
    MyClass obj(10);
    MyClass copiedObj(obj);
    std::cout << "Copied data (read): " << copiedObj.getData() << std::endl;
}

void writeThreadFunction() {
    MyClass obj(10);
    obj.setData(20);
}

int main() {
    std::thread t1(readThreadFunction);
    std::thread t2(readThreadFunction);
    std::thread t3(writeThreadFunction);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}