面试题答案
一键面试可能遇到的问题
- 数据竞争:静态成员函数可能会访问和修改静态数据成员。在多线程环境下,多个线程同时访问和修改静态数据成员可能导致数据不一致的问题。例如,一个静态计数器被多个线程同时递增,可能会出现计数错误。
- 资源冲突:如果静态成员函数涉及到共享资源(如文件、网络连接等)的操作,多个线程同时访问这些资源可能导致资源冲突,例如文件写入混乱等问题。
解决方法
- 加锁机制:使用互斥锁(
std::mutex
)来保护对静态数据成员和共享资源的访问。只有获取到锁的线程才能执行关键代码段,从而避免数据竞争和资源冲突。 - 线程局部存储(TLS):对于一些需要每个线程独立拥有的数据,可以使用线程局部存储。每个线程都有自己独立的副本,避免了多线程对同一数据的竞争。不过这种方法不适合共享数据的场景,对于静态成员函数访问共享数据不太适用。
加锁机制示例
#include <iostream>
#include <mutex>
#include <thread>
class MyClass {
public:
static int counter;
static std::mutex mtx;
static void increment() {
std::lock_guard<std::mutex> lock(mtx);
counter++;
}
static void printCounter() {
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Counter value: " << counter << std::endl;
}
};
int MyClass::counter = 0;
std::mutex MyClass::mtx;
void threadFunction() {
for (int i = 0; i < 1000; ++i) {
MyClass::increment();
}
MyClass::printCounter();
}
int main() {
std::thread threads[10];
for (int i = 0; i < 10; ++i) {
threads[i] = std::thread(threadFunction);
}
for (auto& thread : threads) {
thread.join();
}
return 0;
}
在上述示例中:
MyClass
类有一个静态数据成员counter
和一个静态互斥锁mtx
。increment
静态成员函数用于递增counter
,在操作前通过std::lock_guard<std::mutex> lock(mtx);
来获取锁,操作完成后自动释放锁。printCounter
静态成员函数用于打印counter
的值,同样在操作前获取锁,保证数据的一致性。- 在
main
函数中创建了 10 个线程同时调用increment
和printCounter
函数,通过加锁机制确保了counter
在多线程环境下的安全访问。