C++ 多线程面试题解答与代码示例
在当今的多核处理器时代,多线程编程已经成为提高程序性能的关键技术。C++ 作为一种支持多线程的编程语言,在面试中经常被问到关于多线程的问题。本文将围绕 C++ 多线程面试题,结合代码示例进行解答。
多线程编程涉及到线程的创建、同步、通信等多个方面。以下是一些常见的多线程面试题及其解答。
1. 什么是线程?
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器和栈),但是它可以与同属一个进程的其他线程共享进程所拥有的全部资源。
2. C++ 中如何创建线程?
在 C++ 中,可以使用 `` 头文件中的 `thread` 类来创建线程。
cpp
include
void function() {
// 线程执行的代码
}
int main() {
std::thread t(function); // 创建线程
t.join(); // 等待线程结束
return 0;
}
3. 什么是线程同步?
线程同步是指多个线程在执行过程中,通过某种机制来协调彼此的行为,以保证数据的一致性和程序的正确性。
4. C++ 中有哪些线程同步机制?
C++ 提供了多种线程同步机制,包括互斥锁(mutex)、条件变量(condition_variable)、原子操作(atomic)等。
4.1 互斥锁(mutex)
互斥锁用于保护共享资源,确保同一时刻只有一个线程可以访问该资源。
cpp
include
std::mutex mtx;
void sharedResource() {
std::lock_guard lock(mtx); // 自动加锁
// 访问共享资源
}
int main() {
std::thread t1(sharedResource);
std::thread t2(sharedResource);
t1.join();
t2.join();
return 0;
}
4.2 条件变量(condition_variable)
条件变量用于线程间的同步,允许一个或多个线程等待某个条件成立。
cpp
include
include
include
std::condition_variable cv;
std::mutex mtx;
bool ready = false;
void waitThread() {
std::unique_lock lock(mtx);
cv.wait(lock, []{ return ready; }); // 等待条件成立
// 执行任务
}
void signalThread() {
std::unique_lock lock(mtx);
ready = true;
cv.notify_one(); // 通知一个等待的线程
}
int main() {
std::thread t1(waitThread);
std::thread t2(signalThread);
t1.join();
t2.join();
return 0;
}
4.3 原子操作(atomic)
原子操作用于保证操作的原子性,防止数据竞争。
cpp
include
std::atomic counter(0);
void increment() {
counter.fetch_add(1, std::memory_order_relaxed); // 原子增加
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Counter: " << counter.load(std::memory_order_relaxed) << std::endl;
return 0;
}
5. 什么是死锁?
死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法继续执行。
6. 如何避免死锁?
为了避免死锁,可以采取以下措施:
- 使用资源有序分配策略,确保线程按照相同的顺序请求资源。
- 使用超时机制,当线程请求资源失败时,可以等待一段时间后重新尝试或放弃。
- 使用检测算法,定期检测系统中是否存在死锁,并采取措施解除死锁。
7. 什么是线程池?
线程池是一种管理线程的机制,它预先创建一定数量的线程,并将任务分配给这些线程执行。线程池可以提高程序的性能,减少线程创建和销毁的开销。
8. C++ 中如何实现线程池?
在 C++ 中,可以使用第三方库如 `boost::asio` 或自己实现线程池。
以下是一个简单的线程池实现示例:
cpp
include
include
include
include
include
include
class ThreadPool {
public:
ThreadPool(size_t threads) : stop(false) {
for (size_t i = 0; i < threads; ++i) {
workers.emplace_back([this] {
for (;;) {
std::function task;
{
std::unique_lock lock(this->queue_mutex);
this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
if (this->stop && this->tasks.empty())
return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
});
}
}
template
auto enqueue(F&& f, Args&&... args)
-> std::future<#typename std::result_of::type> {
using return_type = typename std::result_of::type;
auto task = std::make_shared< std::packaged_task >(
std::bind(std::forward(f), std::forward(args)...)
);
std::future res = task->get_future();
{
std::unique_lock lock(queue_mutex);
if (stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace(
}
condition.notify_one();
return res;
}
~ThreadPool() {
{
std::unique_lock lock(queue_mutex);
stop = true;
}
condition.notify_all();
for (std::thread &worker: workers)
worker.join();
}
private:
std::vector workers;
std::queue< std::function > tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
int main() {
ThreadPool pool(4);
auto future1 = pool.enqueue([](int x, int y) { return x + y; }, 1, 2);
auto future2 = pool.enqueue([](int x, int y) { return x y; }, 3, 4);
std::cout << "Result 1: " << future1.get() << std::endl;
std::cout << "Result 2: " << future2.get() << std::endl;
return 0;
}
总结
本文围绕 C++ 多线程面试题,结合代码示例进行了详细的解答。通过学习本文,读者可以掌握 C++ 多线程编程的基本概念、同步机制、线程池等知识,为面试和实际开发打下坚实的基础。
Comments NOTHING