面试之手撸安全队列
- 1. 代码
- 2. 测试
最近体验了一下面试,面试官要求用C++实现一个安全队列,要求是:
- 插入或读取数据时,有超时时间;
- 队列有长度限制,最大支持max_size;
- 该队列是线程安全的;
闲语不多说,直接上干货。
1. 代码
#include<iostream>
#include<queue>
#include<mutex>
#include<condition_variable>
#include<chrono>
#include<thread>
#include<algorithm>using namespace std;
template<typename T>
class FySafeQueue{using Queue = std::queue<T>;
public:explicit FySafeQueue(uint max_size, uint16_t timeout):fy_max_size_(max_size),fy_timeout_(timeout){}FySafeQueue(FySafeQueue& queue){std::unique_lock<std::mutex> lg(this->fy_mtx);this->fy_max_size_ = queue.fy_max_size_;this->fy_timeout_ = queue.fy_timeout_;this->fy_queue_ = queue.fy_queue_;}FySafeQueue(FySafeQueue&& queue){std::unique_lock<std::mutex> lg(this->fy_mtx);this->fy_max_size_ = queue.fy_max_size_;this->fy_timeout_ = queue.fy_timeout_;this->fy_queue_ = queue.fy_queue_;}FySafeQueue operator=(FySafeQueue& queue){std::unique_lock<std::mutex> lg(this->fy_mtx);this->fy_max_size_ = queue.fy_max_size_;this->fy_timeout_ = queue.fy_timeout_;this->fy_queue_ = queue.fy_queue_;}~FySafeQueue(){this->fy_write_cv_.notify_all();this->fy_read_cv_.notify_all();}bool pop(T &obj){std::unique_lock<std::mutex> lg(this->fy_mtx);auto ret = fy_read_cv_.wait_for(lg, std::chrono::milliseconds(this->fy_timeout_),[this]{ return !this->fy_queue_.empty(); } );if (ret){obj = this->fy_queue_.front();this->fy_queue_.pop();this->fy_write_cv_.notify_one();return true;}return false;}bool push(T &obj){std::unique_lock<std::mutex> lg(this->fy_mtx);auto ret = fy_write_cv_.wait_for(lg, std::chrono::milliseconds(this->fy_timeout_),[this]{ return this->fy_queue_.size() < this->fy_max_size_; } );if (ret){this->fy_queue_.push(obj);this->fy_read_cv_.notify_one();return true;}return false;}size_t size(){std::unique_lock<std::mutex> lg(this->fy_mtx);return this->fy_queue_.size();}void clear(){std::unique_lock<std::mutex> lg(this->fy_mtx);while(!this->fy_queue_.empty()){fy_queue_.pop();}}private:uint fy_max_size_;uint16_t fy_timeout_; // unit: msQueue fy_queue_;std::mutex fy_mtx;std::condition_variable fy_read_cv_;std::condition_variable fy_write_cv_;
};FySafeQueue<int> glb_test_queue(2, 10);void read_data();
void write_data(int data);int main(int argc, char**argv){std::cout << "*******************safety queue test********************" << std::endl;std::cout << "1. signal thread test....................................." << std::endl;int a = 16;glb_test_queue.push(a);std::cout << "glb_test_queue size: " << glb_test_queue.size() << std::endl;int result;if (glb_test_queue.pop(result)){std::cout << "result: " << result << std::endl;} else {std::cout << "get data from glb_test_queue failed." << std::endl;}glb_test_queue.clear();std::cout << "\n\n" << std::endl;std::cout << "2. multi thread test....................................." << std::endl;std::thread th1(write_data, 12);std::thread th2(write_data, 11);std::thread th3(write_data, 10);std::this_thread::sleep_for(std::chrono::milliseconds(30));std::cout << "queue size: " << glb_test_queue.size() << std::endl;std::thread th4(read_data);std::thread th5(read_data);if (th1.joinable()) th1.join();if (th2.joinable()) th2.join();if (th3.joinable()) th3.join();if (th4.joinable()) th4.join();if (th5.joinable()) th5.join();glb_test_queue.clear();std::cout << "\n\n" << std::endl;std::cout << "3. safety queue copy and operator= function test....................................." << std::endl;write_data(22);write_data(23);write_data(24);FySafeQueue<int> copy_queue(glb_test_queue);if (copy_queue.pop(result)){std::cout << "copy_queue, result: " << result << std::endl;} else {std::cout << "get data from copy_queue failed." << std::endl;}FySafeQueue<int> operator_queue = glb_test_queue;if (operator_queue.pop(result)){std::cout << "operator_queue, result: " << result << std::endl;} else {std::cout << "get data from operator_queue failed." << std::endl;}std::this_thread::sleep_for(std::chrono::milliseconds(100));std::cout << "\n\n" << std::endl;std::cout << "*******************safety queue test success********************" << std::endl;
}void read_data(){int result;if (glb_test_queue.pop(result)){std::cout << "thread id: " << std::this_thread::get_id() << ", result: " << result << std::endl;} else {std::cout << "get data from glb_test_queue failed." << std::endl;}
}void write_data(int data){if (glb_test_queue.push(data) )std::cout << "insert data to glb_test_queue success." << std::endl;elsestd::cout << "insert data to glb_test_queue failed, data: " << data << std::endl;
}
2. 测试
本次测试主要 分为三部分:
- 单线程测试,即主线程进行push&pop函数的测试;
- 多线程测试,多线程进行读和写的操作,以及最大长度测试;
- 测试拷贝构造和赋值函数。
代码已经在上文,这里直接上日志
*******************safety queue test********************
1. signal thread test.....................................
glb_test_queue size: 1
result: 162. multi thread test.....................................
insert data to glb_test_queue success.
insert data to glb_test_queue success.
insert data to glb_test_queue failed, data: 10
queue size: 2
thread id: 140324334204672, result: 12
thread id: 140324325811968, result: 113. safety queue copy and operator= function test.....................................
insert data to glb_test_queue success.
insert data to glb_test_queue success.
insert data to glb_test_queue failed, data: 24
copy_queue, result: 22
operator_queue, result: 22*******************safety queue test success********************