面试之手撸安全队列

面试之手撸安全队列

  • [1. 代码](#1. 代码)
  • [2. 测试](#2. 测试)

最近体验了一下面试,面试官要求用C++实现一个安全队列,要求是:

  1. 插入或读取数据时,有超时时间;
  2. 队列有长度限制,最大支持max_size;
  3. 该队列是线程安全的;

闲语不多说,直接上干货。

1. 代码

c++ 复制代码
#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: ms
	Queue         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;
	else
		std::cout << "insert data to glb_test_queue failed, data: " << data << std::endl;
}

2. 测试

本次测试主要 分为三部分:

  1. 单线程测试,即主线程进行push&pop函数的测试;
  2. 多线程测试,多线程进行读和写的操作,以及最大长度测试;
  3. 测试拷贝构造和赋值函数。

代码已经在上文,这里直接上日志

*******************safety queue test********************
1. signal thread test.....................................
glb_test_queue size: 1
result: 16



2. 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: 11



3. 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********************
相关推荐
程序猿阿伟2 小时前
《C++:计算机视觉图像识别与目标检测算法优化的利器》
c++·目标检测·计算机视觉
Enoch8883 小时前
Day25 C++ 文件和流
开发语言·c++·cocoa
{⌐■_■}3 小时前
【c++】自定义命名空间namespace与头文件的组织与企业应用案例
服务器·数据库·c++
界面开发小八哥3 小时前
MFC扩展库BCGControlBar Pro v36.0 - 工具栏 & 对话框组件升级
c++·mfc·bcg·界面控件·ui开发
小帆的帆4 小时前
vscode+msys2+clang+xmake c++开发环境搭建
c++·ide·vscode
真想骂*5 小时前
详解C++中“virtual”的概念及其含义
java·jvm·c++
薔薇十字5 小时前
【代码随想录day62】【C++复健】 97. 小明逛公园(Floyd 算法精讲);127. 骑士的攻击(A * 算法精讲)
开发语言·c++·算法
-指短琴长-5 小时前
Linux从0到1——线程自定义封装
linux·运维·c++
SUN_Gyq6 小时前
C++如何实现对象的克隆?如何实现单例模式?
java·开发语言·jvm·c++·算法