面试题答案
一键面试利用多线程技术实现并发处理
在C++网络编程中,为了同时处理多个客户端请求,可以为每个客户端请求创建一个新线程来处理,或者使用线程池。
- 为每个请求创建新线程: 当有新的客户端连接时,创建一个新的线程来处理该客户端的通信。例如:
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <functional>
#include <vector>
#include <chrono>
// 模拟处理客户端请求的函数
void handleClient(int clientId) {
std::cout << "Handling client " << clientId << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Finished handling client " << clientId << std::endl;
}
在服务器主循环中:
int main() {
for (int i = 0; i < 5; ++i) {
std::thread t(handleClient, i);
t.detach();
}
std::this_thread::sleep_for(std::chrono::seconds(5));
return 0;
}
- 使用线程池: 线程池预先创建一定数量的线程,任务到来时将任务分配给线程池中的线程。
线程安全问题及解决方案
- 数据竞争:
- 问题:多个线程同时访问和修改共享数据,导致数据不一致。
- 解决方案:使用互斥锁(
std::mutex
)、读写锁(std::shared_mutex
)等。例如,保护共享资源sharedData
:
std::mutex dataMutex;
int sharedData = 0;
void modifySharedData() {
std::lock_guard<std::mutex> lock(dataMutex);
sharedData++;
}
-
死锁:
- 问题:两个或多个线程相互等待对方释放资源,导致程序冻结。
- 解决方案:避免嵌套锁,按顺序加锁,使用
std::try_lock
尝试加锁等。
-
条件变量:
- 问题:线程需要等待某个条件满足才能继续执行。
- 解决方案:使用
std::condition_variable
。例如,线程等待共享数据达到某个值:
std::mutex cvMutex;
std::condition_variable cv;
bool dataReady = false;
void waitForData() {
std::unique_lock<std::mutex> lock(cvMutex);
cv.wait(lock, [] { return dataReady; });
std::cout << "Data is ready" << std::endl;
}
void setDataReady() {
{
std::lock_guard<std::mutex> lock(cvMutex);
dataReady = true;
}
cv.notify_one();
}
线程池的设计与使用代码示例
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <functional>
#include <vector>
class ThreadPool {
public:
ThreadPool(size_t numThreads) {
for (size_t i = 0; i < numThreads; ++i) {
threads.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queueMutex);
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();
}
});
}
}
~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread& thread : threads) {
thread.join();
}
}
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queueMutex);
if (stop) throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task]() { (*task)(); });
}
condition.notify_one();
return res;
}
private:
std::vector<std::thread> threads;
std::queue<std::function<void()>> tasks;
std::mutex queueMutex;
std::condition_variable condition;
bool stop = false;
};
// 示例任务
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; ++i) {
result *= i;
}
return result;
}
int main() {
ThreadPool pool(4);
std::vector<std::future<int>> results;
for (int i = 1; i <= 8; ++i) {
results.emplace_back(pool.enqueue(factorial, i));
}
for (auto& res : results) {
std::cout << res.get() << std::endl;
}
return 0;
}
此代码实现了一个简单的线程池,包含线程创建、任务队列管理、线程安全机制以及条件变量的使用。可以将不同的任务通过enqueue
方法提交到线程池中执行。