面试题答案
一键面试安全性挑战
- 数据竞争:多个线程同时调用友元函数访问和修改类的共享成员时,可能导致数据竞争,最终结果具有不确定性,可能出现错误的计算结果或程序崩溃。
- 内存一致性:不同线程对共享数据的访问顺序可能不一致,导致程序出现难以调试的逻辑错误。
同步机制实现安全使用
- 使用互斥锁:
互斥锁(
std::mutex
)可以保证在同一时间只有一个线程能够进入临界区,访问共享数据。
#include <iostream>
#include <mutex>
#include <thread>
class B {
int sharedData;
std::mutex mtx;
public:
B() : sharedData(0) {}
friend void friendThreadFunc(B* obj);
};
void friendThreadFunc(B* obj) {
// 锁定互斥锁
std::lock_guard<std::mutex> lock(obj->mtx);
// 访问和修改共享数据
obj->sharedData++;
std::cout << "Thread modified sharedData to: " << obj->sharedData << std::endl;
}
int main() {
B b;
std::thread t1(friendThreadFunc, &b);
std::thread t2(friendThreadFunc, &b);
t1.join();
t2.join();
return 0;
}
- 使用条件变量:
条件变量(
std::condition_variable
)通常与互斥锁配合使用,用于线程间的同步。当某个条件满足时,通知等待的线程。但在简单的修改共享数据场景下,条件变量不是必需的。如果在友元函数中需要根据共享数据的某个条件进行等待,可使用如下方式:
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
class B {
int sharedData;
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
public:
B() : sharedData(0) {}
friend void friendThreadFunc(B* obj);
};
void friendThreadFunc(B* obj) {
std::unique_lock<std::mutex> lock(obj->mtx);
// 等待条件满足
obj->cv.wait(lock, [&obj] { return obj->ready; });
// 访问和修改共享数据
obj->sharedData++;
std::cout << "Thread modified sharedData to: " << obj->sharedData << std::endl;
}
int main() {
B b;
std::thread t1(friendThreadFunc, &b);
// 模拟一些工作
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::lock_guard<std::mutex> lock(b.mtx);
b.ready = true;
}
b.cv.notify_one();
t1.join();
return 0;
}
上述代码中,std::lock_guard
构造时自动锁定互斥锁,析构时自动解锁,确保临界区代码的安全执行。std::unique_lock
与条件变量配合使用,等待条件满足时才执行后续操作。