面试题答案
一键面试线程创建
在C++ 中,可以使用<thread>
库来创建线程。以下是一个简单的示例,展示如何创建一个线程:
#include <iostream>
#include <thread>
void task() {
std::cout << "子线程正在执行任务" << std::endl;
}
int main() {
std::thread t(task);
t.join();
std::cout << "主线程等待子线程完成" << std::endl;
return 0;
}
同步机制
为了确保子线程执行完任务后主线程能够得到通知,可以使用条件变量(std::condition_variable
)和互斥锁(std::mutex
)来实现同步。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
std::mutex mtx;
std::condition_variable cv;
std::atomic<bool> taskCompleted(false);
void task() {
std::cout << "子线程正在执行任务" << std::endl;
// 模拟任务执行
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::lock_guard<std::mutex> lock(mtx);
taskCompleted = true;
}
cv.notify_one();
}
int main() {
std::thread t(task);
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{return taskCompleted;});
std::cout << "主线程收到子线程完成的通知" << std::endl;
t.join();
return 0;
}
回调函数的设计和调用
可以将回调函数作为参数传递给子线程的任务函数。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
std::mutex mtx;
std::condition_variable cv;
std::atomic<bool> taskCompleted(false);
using Callback = void(*)();
void task(Callback callback) {
std::cout << "子线程正在执行任务" << std::endl;
// 模拟任务执行
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::lock_guard<std::mutex> lock(mtx);
taskCompleted = true;
}
cv.notify_one();
if (callback) {
callback();
}
}
void callbackFunction() {
std::cout << "回调函数被调用" << std::endl;
}
int main() {
std::thread t(task, callbackFunction);
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{return taskCompleted;});
std::cout << "主线程收到子线程完成的通知" << std::endl;
t.join();
return 0;
}
线程安全问题及解决方案
-
竞态条件(Race Condition):当多个线程同时访问和修改共享资源时,可能会导致数据不一致。例如,在没有适当同步的情况下,多个线程同时修改
taskCompleted
变量。- 解决方案:使用互斥锁(
std::mutex
)来保护共享资源。在访问共享资源前加锁,访问完成后解锁。例如在修改taskCompleted
变量前后使用std::lock_guard<std::mutex>
来自动管理锁的生命周期。
- 解决方案:使用互斥锁(
-
死锁(Deadlock):当两个或多个线程相互等待对方释放锁时,会发生死锁。例如,线程A持有锁1并等待锁2,而线程B持有锁2并等待锁1。
- 解决方案:避免嵌套锁,确保线程以相同的顺序获取锁。如果必须使用多个锁,使用
std::lock
函数一次性获取多个锁,该函数可以避免死锁。
- 解决方案:避免嵌套锁,确保线程以相同的顺序获取锁。如果必须使用多个锁,使用
-
条件变量的虚假唤醒(Spurious Wakeup):在某些情况下,条件变量可能在没有调用
notify_one
或notify_all
时被唤醒。- 解决方案:在
wait
函数中使用谓词(predicate),如cv.wait(lock, []{return taskCompleted;});
。这样即使发生虚假唤醒,也会检查谓词条件,只有满足条件时才继续执行。
- 解决方案:在