面试之手撸安全队列

面试之手撸安全队列

  • [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********************
相关推荐
奕天者38 分钟前
C++学习笔记(十七)——类之封装
c++·笔记·学习
亭墨1 小时前
linux0.11内核源码修仙传第六章——中断初始化
linux·c语言·驱动开发·学习·面试
Ljw...1 小时前
序列化和反序列化(Linux)
linux·开发语言·网络·c++·tcp/ip·序列化反序列化
lucky1_1star1 小时前
FX-函数重载、重写(覆盖)、隐藏
java·c++·算法
UestcXiye1 小时前
《TCP/IP网络编程》学习笔记 | Chapter 17:优于 select 的 epoll
c++·网络编程
郭源潮12 小时前
【C++】特殊类的设计 + 单例模式
开发语言·c++
心态与习惯3 小时前
c++ 中的引用 &
c++·指针·数组·引用·ref·容器传递
橘颂TA3 小时前
【C++】数据结构 栈的实现
开发语言·数据结构·c++··学生
武乐乐~4 小时前
欢乐力扣:合并区间
算法·leetcode·职场和发展
WZF-Sang4 小时前
Linux——基础IO【3万字大章】
linux·服务器·c++·学习·文件系统·软硬链接·动态库静态库