Menu

实现一个多线程并发访问的队列

Project1: 实现一个多线程并发访问的队列

Implement a multi-access threaded queue with multiple threads inserting and multiple threads extracting from the queue. Use mutex-locks to synchronize access to the queue. Document the time for 1000 insertions and 1000 extractions each by 64 insertions threads (Producers) and 64 extraction threads (Consumers). 语言限制:C/C++/Java PS:不能直接使用 STL 或者 JDK 中现有的并发访问队列,请基于普通的 queue 或自行实现

实现思路

在继承 STL 中的适配器queue的基础上,每次对容器内元素的访问和修改都需要先上锁,结束后解锁。

由于访问操作可以是const的,因此这个锁需要是mutable的。

运行结果

所用机器型号为 VAIO Z Flip 2016,基本配置如下:

  • Intel(R) Core(TM) i7-6567U CPU @3.30GHZ 3.31GHz
  • 8.00GB RAM

编译运行 main.cpp 后,得到如下运行结果:

1
elapsed time: 0.146981s

即进行 64 个生产者和消费者访问之后一共消耗了约 0.146981s。

源代码

wkMultiAccessQueue.hpp

需要开 C++11。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef _wkMultiAccessQueue_hpp_
#define _wkMultiAccessQueue_hpp_
#include <queue>
#include <mutex>
namespace wk
{
template <class T>
class MultiAccessQueue : std::queue<T>
{
private:
	mutable std::mutex mu;

public:
	void push(T val)
	{
		std::lock_guard<std::mutex> guard(mu);
		std::queue<T>::push(val);
	}
	void pop()
	{
		std::lock_guard<std::mutex> guard(mu);
		std::queue<T>::pop();
	}
	T front() const
	{
		std::lock_guard<std::mutex> guard(mu);
		return std::queue<T>::front();
	}
};
} // namespace wk
#endif

main.cpp

需要开 C++11。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <chrono>
#include <vector>
#include <thread>
#include <iostream>
#include "wkMultiAccessQueue.hpp"
wk::MultiAccessQueue<int> q;
void producer(int cnt)
{
	for (int i = 0; i < cnt; ++i)
		q.push(i);
}
void consumer(int cnt)
{
	for (int i = 0; i < cnt; ++i)
		q.pop();
}
int main()
{
	auto begin = std::chrono::system_clock::now();
	std::vector<std::thread> vt(64);
	for (auto &it : vt)
		it = std::thread(producer, 1000);
	for (auto &it : vt)
		it.join();
	for (auto &it : vt)
		it = std::thread(consumer, 1000);
	for (auto &it : vt)
		it.join();
	auto end = std::chrono::system_clock::now();
	std::chrono::duration<double> elapsed_seconds = end - begin;
	std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
}