面试题答案
一键面试1. 内存分配机制
在C++ 中,全局static
变量存储在静态存储区。静态存储区在程序运行期间一直存在,其内存分配在程序加载时就完成。编译器在编译阶段为全局static
变量分配空间,并且在程序启动时,操作系统负责将其初始化(若有初始化值)。
2. 生命周期管理
全局static
变量的生命周期从程序启动开始,直到程序结束。一旦程序加载并初始化了全局static
变量,它就一直存在于内存中,不会随着函数调用或局部作用域的结束而销毁。当程序终止时,操作系统会回收分配给该变量的内存。
3. 多线程环境下的问题
- 初始化问题:在多线程环境中,如果多个线程同时尝试访问尚未初始化的全局
static
变量,可能会导致多次初始化的问题。因为每个线程都可能认为自己是第一个访问该变量的线程,从而重复进行初始化操作。 - 数据竞争问题:如果多个线程对全局
static
变量进行读写操作,可能会引发数据竞争。例如,一个线程正在读取变量值,另一个线程同时在修改它,这会导致读取到的数据不一致或出现未定义行为。
4. 解决方法
- 使用局部
static
变量(C++11及以后):在函数内部使用static
变量,C++11标准保证了局部static
变量的初始化是线程安全的。只有第一个进入函数并尝试初始化该局部static
变量的线程会进行初始化操作,其他线程会等待初始化完成。例如:
#include <iostream>
#include <thread>
class MyClass {
public:
MyClass() {
std::cout << "MyClass constructor" << std::endl;
}
};
MyClass& getInstance() {
static MyClass instance;
return instance;
}
void threadFunction() {
MyClass& obj = getInstance();
}
int main() {
std::thread t1(threadFunction);
std::thread t2(threadFunction);
t1.join();
t2.join();
return 0;
}
- 双检查锁定(DCL):在C++11之前,可以使用双检查锁定机制。不过,在早期的C++标准中,由于内存模型的问题,该方法并不完全可靠。但在C++11及以后,通过使用
std::atomic
和std::memory_order
可以实现安全的双检查锁定。例如:
#include <iostream>
#include <atomic>
#include <mutex>
class Singleton {
private:
static std::atomic<Singleton*> instance;
static std::mutex mtx;
Singleton() {}
~Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton* getInstance() {
Singleton* tmp = instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(mtx);
tmp = instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton();
std::atomic_thread_fence(std::memory_order_release);
instance.store(tmp, std::memory_order_relaxed);
}
}
return tmp;
}
};
std::atomic<Singleton*> Singleton::instance(nullptr);
std::mutex Singleton::mtx;
void threadFunction() {
Singleton* obj = Singleton::getInstance();
}
int main() {
std::thread t1(threadFunction);
std::thread t2(threadFunction);
t1.join();
t2.join();
return 0;
}
- 使用互斥锁(Mutex):在对全局
static
变量进行读写操作时,使用互斥锁来保护对变量的访问。例如:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex globalMutex;
static int globalStaticVar = 0;
void increment() {
std::lock_guard<std::mutex> lock(globalMutex);
globalStaticVar++;
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "globalStaticVar: " << globalStaticVar << std::endl;
return 0;
}