//!
//! C++工具:STL容器多线程接口封装--多线程接口安全
//!
//! ===== 多线程容器简介 =====
//! 多线程安全容器指的是在多个线程同时操作同一个容器时,总是保证数据同步的,
//! 但C++STL标准容器中不提供线程安全的容器,保证线程安全需要消耗更多的时间等待操作,
//! 本章封装了STL容器中的部分容器,采用保护继承的方式尽最大可能保留原始STL容器接口
//! 主要封装方式为对所有接口加锁,保证容器接口线程安全,但不保证迭代器的线程安全,
//! 多线程操作迭代器存在迭代器易位情况, 如果需要操作迭代器需要自行加锁
//! 因为STL容器存在可保存的迭代器直接指向内存地址,导致很难保证线程安全,
//! 如果需要实现线程安全的容器,迭代器不应该保留,如此以来也失去了操作数据的灵活性
//! ===== 多线程容器简介 =====
//!
//!
//! ===== 提供的封装容器 =====
//! queue_th : queue 管道容器代表
//! map_th : map 索引容器代表
//! vector_th : vector 线性容器代表
//! ===== 提供的封装容器 =====
//!
//!
//! ===== 迭代器易位 =====
//! 迭代器易位的场景,如vector容器在多线程下扩容,导致其他线程的迭代器全部失效,
//! 或者容器数据改变,导致迭代器的数据顺序改变,如map的insert函数被连续调用,
//! 导致其他线程提前保存的begin迭代器可能改变位置,迭代器失效
//! ===== 迭代器易位 =====
//!
//!
//! ===== 内容展示顺序 =====
//! 1.queue_th.h
//! 2.map_th.h
//! 3.vector_th.h
//! 4.main.h (包含容器测试函数)
//! ===== 内容展示顺序 =====
//!
//! 结束语:
//! 可以提供简易的多线程容器应用场景,但是不保证所有操作的安全性,
//! 如果需要大量多线程的场景请选择真正线程安全的容器
//!
#ifndef QUEUE_TH_H
#define QUEUE_TH_H
#include <queue>
#include <deque>
#include <mutex>
#include <memory>
//!
//! 功能: 对queue容器加锁,保证多线程下调用接口安全,不保证迭代器安全
//! 原理:保护继承queue容器,实现大部分函数接口, 使用继承构造获取大部分父类构造函数
//!
template<typename _Tp, typename _Sequence = std::deque<_Tp> >
class queue_th : protected std::queue<_Tp,_Sequence>
{
public:
//C++STD
typedef typename _Sequence::value_type value_type;
typedef typename _Sequence::reference reference;
typedef typename _Sequence::size_type size_type;
//this class
typedef std::queue<_Tp,_Sequence> parent;
typedef std::lock_guard<std::mutex> lock_t;
public:
using std::queue<_Tp,_Sequence>::queue;
//拷贝底层deque容器的数据到queue_th,需要覆盖父类的拷贝构造和赋值重载
explicit queue_th(const queue_th& __q) : parent(__q) {}
explicit queue_th(queue_th&& __q) : parent(std::move(__q)) {}
void operator=(const queue_th& __q) { this->c = __q.c; }
void operator=(queue_th&& __q) { this->c = std::move(__q.c); }
void pop() { lock_t lock(_mutex); this->parent::pop(); }
reference back() { lock_t lock(_mutex); return this->parent::back(); }
reference front() { lock_t lock(_mutex); return this->parent::front(); }
size_type size() { lock_t lock(_mutex); return this->parent::size(); }
bool empty() { lock_t lock(_mutex); return this->parent::empty(); }
void swap(queue_th& __q)
{ lock_t lock(_mutex); std::swap(this->c, __q.c); }
void push(const value_type& __x)
{ lock_t lock(_mutex); this->parent::push(__x); }
void push(value_type&& __x)
{ lock_t lock(_mutex); this->parent::push(std::move(__x)); }
template<typename... _Args>
void emplace(_Args&&... __args)
{ lock_t lock(_mutex); this->parent::emplace(std::forward<_Args>(__args)...); }
protected:
std::mutex _mutex;
};
#endif // QUEUE_TH_H
#ifndef MAP_TH_H
#define MAP_TH_H
#include <map>
#include <mutex>
#include <memory>
//!
//! 功能: 对map容器加锁,保证多线程下调用接口安全,不保证迭代器安全
//! 原理:保护继承map容器,实现大部分函数接口, 使用继承构造获取大部分父类构造函数
//!
template <typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
class map_th : protected std::map<_Key,_Tp,_Compare,_Alloc>
{
public:
typedef _Key key_type;
typedef _Tp mapped_type;
typedef std::pair<const _Key, _Tp> value_type;
typedef _Compare key_compare;
typedef _Alloc allocator_type;
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::
template rebind<value_type>::other _Pair_alloc_type;
typedef std::_Rb_tree<key_type, value_type, std::_Select1st<value_type>,
key_compare, _Pair_alloc_type> _Rep_type;
typedef __gnu_cxx::__alloc_traits<_Pair_alloc_type> _Alloc_traits;
typedef typename _Alloc_traits::pointer pointer;
typedef typename _Alloc_traits::const_pointer const_pointer;
typedef typename _Alloc_traits::reference reference;
typedef typename _Alloc_traits::const_reference const_reference;
typedef typename _Rep_type::iterator iterator;
typedef typename _Rep_type::const_iterator const_iterator;
typedef typename _Rep_type::size_type size_type;
typedef typename _Rep_type::difference_type difference_type;
typedef typename _Rep_type::reverse_iterator reverse_iterator;
typedef typename _Rep_type::const_reverse_iterator const_reverse_iterator;
//this class
typedef std::map<_Key,_Tp,_Compare,_Alloc> parent;
typedef std::lock_guard<std::mutex> lock_t;
public:
//继承构造函数,并覆盖父类的拷贝构造
using std::map<_Key,_Tp,_Compare,_Alloc>::map;
map_th(const map_th& __m) : parent(__m) {}
map_th(map_th&& __m) : parent(std::move(__m)) {}
mapped_type& at(const key_type& __k)
{ lock_t lock(_mutex); return parent::at(__k); }
mapped_type& operator[](const key_type& __k)
{ lock_t lock(_mutex); return parent::operator[](__k); }
mapped_type& operator[](key_type&& __k)
{ lock_t lock(_mutex); return parent::operator[](std::forward<key_type>(__k)); }
iterator begin() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::begin(); }
iterator end() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::end(); }
reverse_iterator rbegin() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::rbegin(); }
reverse_iterator rend() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::rend(); }
iterator find(const key_type& __x)
{ lock_t lock(_mutex); return parent::find(__x); }
void clear() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::clear(); }
iterator erase(const_iterator __position)
{ lock_t lock(_mutex); return parent::erase(__position); }
iterator erase(iterator __position)
{ lock_t lock(_mutex); return parent::erase(__position); }
size_type erase(const key_type& __x)
{ lock_t lock(_mutex); return parent::erase(__x); }
iterator erase(const_iterator __first, const_iterator __last)
{ lock_t lock(_mutex); return parent::erase(__first,__last); }
std::pair<iterator, bool> insert(const value_type& __x)
{ lock_t lock(_mutex); return parent::insert(__x); }
std::pair<iterator, bool> insert(value_type&& __x)
{ lock_t lock(_mutex); return parent::insert(move(__x)); }
template<typename _Pair>
std::__enable_if_t<std::is_constructible<value_type, _Pair>::value,std::pair<iterator, bool>>
insert(_Pair&& __x)
{ lock_t lock(_mutex); return parent::insert(std::forward<_Pair>(__x)); }
void insert(std::initializer_list<value_type> __list)
{ lock_t lock(_mutex); return parent::insert(__list); }
iterator insert(const_iterator __position, const value_type& __x)
{ lock_t lock(_mutex); return parent::insert(__position,__x); }
iterator insert(const_iterator __position, value_type&& __x)
{ lock_t lock(_mutex); return parent::insert(__position,move(__x)); }
template<typename _Pair>
std::__enable_if_t<std::is_constructible<value_type, _Pair>::value, iterator>
insert(const_iterator __position, _Pair&& __x)
{ lock_t lock(_mutex); return parent::insert(__position,std::forward<_Pair>(__x)); }
template<typename _InputIterator>
void insert(_InputIterator __first, _InputIterator __last)
{ lock_t lock(_mutex); return parent::insert(__first,__last); }
template<typename... _Args>
std::pair<iterator, bool> emplace(_Args&&... __args)
{ lock_t lock(_mutex); return parent::emplace(std::forward<_Args>(__args)...); }
template<typename... _Args>
iterator emplace_hint(const_iterator __pos, _Args&&... __args)
{ lock_t lock(_mutex); return parent::emplace_hint(__pos,std::forward<_Args>(__args)...); }
_GLIBCXX_NODISCARD bool empty() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::empty(); }
size_type size() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::size(); }
size_type max_size() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::max_size(); }
protected:
std::mutex _mutex;
};
#endif // MAP_TH_H
#ifndef VECTOR_TH_H
#define VECTOR_TH_H
#include <vector>
#include <mutex>
#include <memory>
//!
//! 功能: 对vector容器加锁,保证多线程下调用接口安全,不保证迭代器安全
//! 原理:保护继承vector容器,实现大部分函数接口, 使用继承构造获取大部分父类构造函数
//!
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector_th : protected std::vector<_Tp, _Alloc>
{
public:
//this class
typedef std::lock_guard<std::mutex> lock_t;
typedef std::vector<_Tp, _Alloc> vector;
typedef std::vector<_Tp, _Alloc> parent;
//C++STD
typedef std::_Vector_base<_Tp, _Alloc> _Base;
typedef typename _Base::_Tp_alloc_type _Tp_alloc_type;
typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits;
typedef _Tp value_type;
typedef typename _Base::pointer pointer;
typedef typename _Alloc_traits::const_pointer const_pointer;
typedef typename _Alloc_traits::reference reference;
typedef typename _Alloc_traits::const_reference const_reference;
typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
typedef __gnu_cxx::__normal_iterator<const_pointer, vector> const_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Alloc allocator_type;
//this class
using std::vector<_Tp, _Alloc>::vector;
//C++STD
using _Base::_M_allocate;
using _Base::_M_deallocate;
using _Base::_M_impl;
using _Base::_M_get_Tp_allocator;
public:
explicit vector_th(const vector_th& __x) : parent(__x) {}
explicit vector_th(vector_th&& __x) : parent(std::move(__x)) {}
reference operator[](size_type __n) _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return this->parent::operator[](__n); }
reference at(size_type __n)
{ lock_t lock(_mutex); return parent::at(__n); }
iterator begin() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::begin(); }
iterator end() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::end(); }
reverse_iterator rbegin() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::rbegin(); }
reverse_iterator rend() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::rend(); }
reference back() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::back(); }
_Tp* data() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::data(); }
void clear() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); parent::clear(); }
reference front() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::front(); }
void swap(vector& __x) _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); parent::swap(__x); }
iterator erase(const_iterator __first, const_iterator __last)
{ lock_t lock(_mutex); return parent::erase(__first,__last); }
iterator erase(const_iterator __position)
{ lock_t lock(_mutex); return parent::erase(__position); }
void assign(size_type __n, const value_type& __val)
{ lock_t lock(_mutex); parent::assign(__n,__val); }
template<typename _InputIterator, typename = std::_RequireInputIter<_InputIterator>>
void assign(_InputIterator __first, _InputIterator __last)
{ lock_t lock(_mutex); parent::assign(__first,__last); }
void assign(std::initializer_list<value_type> __l)
{ lock_t lock(_mutex); parent::assign(__l); }
iterator insert(const_iterator __position, const value_type& __x)
{ lock_t lock(_mutex); return parent::insert(__position,__x); }
iterator insert(const_iterator __position, value_type&& __x)
{ lock_t lock(_mutex); return parent::insert(__position,std::move(__x)); }
iterator insert(const_iterator __position, std::initializer_list<value_type> __l)
{ lock_t lock(_mutex); return parent::insert(__position,__l); }
iterator insert(const_iterator __position, size_type __n, const value_type& __x)
{ lock_t lock(_mutex); return parent::insert(__position,__n,__x); }
template<typename _InputIterator, typename = std::_RequireInputIter<_InputIterator>>
iterator insert(const_iterator __position, _InputIterator __first, _InputIterator __last)
{ lock_t lock(_mutex); return parent::insert(__position,__first,__last); }
void resize(size_type __new_size)
{ lock_t lock(_mutex); parent::resize(__new_size); }
void resize(size_type __new_size, const value_type& __x)
{ lock_t lock(_mutex); parent::resize(__new_size,__x); }
void reserve(size_type __n)
{ lock_t lock(_mutex); parent::reserve(__n); }
void pop_back() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); parent::pop_back(); }
void push_back(const value_type& __x)
{ lock_t lock(_mutex); parent::push_back(__x); }
void push_back(value_type&& __x)
{ lock_t lock(_mutex); parent::push_back(std::move(__x)); }
size_type size() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::size(); }
size_type max_size() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::max_size(); }
_GLIBCXX_NODISCARD
bool empty() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::empty(); }
template<typename... _Args>
iterator emplace(const_iterator __position, _Args&&... __args)
{ lock_t lock(_mutex); return parent::emplace(__position,std::forward<_Args>(__args)...); }
size_type capacity() _GLIBCXX_NOEXCEPT
{ lock_t lock(_mutex); return parent::capacity(); }
template<typename... _Args>
void emplace_back(_Args&&... __args)
{ lock_t lock(_mutex); parent::emplace_back(std::forward<_Args>(__args)...); }
protected:
std::mutex _mutex;
};
#endif // VECTOR_TH_H
void test_3()
{
//基本类型操作测试
cout<<endl<<"===== queue_th ====="<<endl;
queue_th<int> thq1;
thq1.push(11);
thq1.push(12);
thq1.push(13);
thq1.push(14);
thq1.push(15);
queue_th<int> thq2(thq1);
queue_th<int> thq3;
thq3 = std::move(thq2);
cout<<"====="<<endl;
while(thq3.empty() == false)
{
cout<<thq3.front()<<endl;
thq3.pop();
}
//类操作测试
queue_th<string> th1;
th1.push("s11");
th1.push("s22");
th1.push("s33");
th1.push("s44");
string s55 = "s55";
th1.push(s55);
th1.emplace("s66");
string s77 = "s77";
th1.emplace(s77);
queue_th<string> th2(std::move(th1));
queue_th<string> th3;
th3 = th2;
cout<<"====="<<endl;
while(th2.size() > 0)
{
cout<<th2.front()<<endl;
th2.pop();
}
//多线程测试
cout<<"====="<<endl;
queue_th<string> queue_th_1;
auto func_th = [&](){
for(int i=0;i<100;i++)
{
string str = "pp: " + to_string(i);
queue_th_1.push(str);
queue_th_1.push(std::move(str));
}
};
thread thread_1(func_th);
thread thread_2(func_th);
thread thread_3(func_th);
thread_1.join();
thread_2.join();
thread_3.join();
cout<<queue_th_1.size()<<endl;
//容器赋值与交换测试
queue_th<string> queue_th_2(queue_th_1);
queue_th<string> queue_th_3;
queue_th_3 = queue_th_1;
queue_th<string> queue_th_tm(queue_th_1);
queue_th<string> queue_th_4(std::move(queue_th_tm));
cout<<"====="<<endl;
cout<<queue_th_2.size()<<endl;
cout<<queue_th_3.size()<<endl;
cout<<queue_th_4.size()<<endl;
queue_th<string> queue_th_null;
cout<<"swap front: "<<queue_th_null.size()<<endl;
queue_th_null.swap(queue_th_4);
cout<<"swap after: "<<queue_th_null.size()<<endl;
}
void test_4()
{
cout<<endl<<"===== vector_th ====="<<endl;
vector_th<string> v1;
v1.push_back("v1");
v1.push_back("v2");
string vv3 = "v3";
v1.push_back(vv3);
string vv4 = "v4";
v1.push_back(std::move(vv4));
v1.emplace_back("v5");
vector_th<string> v2(v1);
vector_th<string> vtm(v1);
vector_th<string> v3(std::move(vtm));
cout<<v1.size()<<endl;
cout<<v2.size()<<endl;
cout<<v3.size()<<endl;
cout<<"====="<<endl;
for(auto a:v2)
{
cout<<a<<endl;
}
cout<<"====="<<endl;
for(auto it = v3.begin();it!=v3.end();it++)
{
cout<<*it<<endl;
}
cout<<"====="<<endl;
cout<<v3.at(2)<<endl;
cout<<v3[3]<<endl;
cout<<"====="<<endl;
v1.emplace(v1.begin(),"v0");
cout<<"capacity: "<<v1.capacity()<<endl;
cout<<"size: "<<v1.size()<<endl;
cout<<"====="<<endl;
for(auto it = v1.begin();it!=v1.end();it++)
{
cout<<*it<<endl;
}
cout<<"====="<<endl;
vector_th<int> veci1;
auto func_th = [&](){
for(int i=0;i<10000;i++)
{
veci1.push_back(i);
}
};
thread thread_1(func_th);
thread thread_2(func_th);
thread thread_3(func_th);
thread_1.join();
thread_2.join();
thread_3.join();
cout<<veci1.size()<<endl;
}
void test_5()
{
cout<<endl<<"===== map_th ====="<<endl;
int v2=20;
int v3=30;
int v5=50;
int v6=60;
//插入测试
map_th<int,int> mm1;
mm1.insert(pair<int,int>(1,10));
mm1.insert(pair<int,int>(2,v2));
mm1.insert(pair<int,int>(3,std::move(v3)));
mm1.emplace(4,40);
mm1.emplace(5,v5);
mm1.emplace(6,std::move(v6));
mm1.emplace_hint(mm1.begin(),pair<int,int>(7,70));
for(const auto &a : mm1)
{
cout<<a.first<<"|"<<a.second<<endl;
}
cout<<mm1.size()<<endl;
//赋值测试
map_th<int,int> mm2(mm1);
map_th<int,int> mm3(std::move(mm1));
cout<<mm2.size()<<endl;
cout<<mm3.size()<<endl;
cout<<mm1.size()<<endl;
auto it = mm2.begin();
for(int i=0;i<3;i++) it++;
mm2.erase(mm2.begin(),it);
cout<<mm2.size()<<endl;
//多线程测试
map_th<int,string> ms1;
ms1.emplace(11,"ss1");
ms1.emplace(12,"ss2");
ms1.emplace(13,"ss3");
ms1.emplace(14,"ss4");
atomic<int> count {0};
auto func = [&](){
for(int i=100;i<1000;i++)
{
count++;
ms1.emplace(i,"push");
}
};
thread t1(func);
thread t2(func);
thread t3(func);
t1.join();
t2.join();
t3.join();
cout<<ms1.size()<<endl;
cout<<count<<endl;
}
#include <unistd.h>
void test_6()
{
//迭代器易位测试
cout<<endl<<"== 迭代器易位测试 =="<<endl;
vector_th<string> v1;
v1.reserve(10);
v1.push_back("word_1");
v1.push_back("word_2");
v1.push_back("word_3");
//初始化的数据量
cout<<v1.capacity()<<"|"<<v1.size()<<endl;
//拿到迭代器,延时时候使用(模拟多线程下被时间切片打断操作)
auto func1 = [&](){
auto it1 = v1.begin();
cout<<"对比点: "<<*it1<<endl;
sleep(1); //延时使得多线程下一定被其他线程插入操作
it1++;
cout<<"对比点: "<<*it1<<endl; //多线程操作迭代器之后,迭代器易位,打印非法数据
};
//往容器添加数据(模拟多线程下迭代器失效)
auto func2 = [&](){
v1.insert(v1.begin()+1,"add word"); //其他线程插入操作
};
cout<<"单线程操作迭代器"<<endl;
func1();
func2();
cout<<"===== show ====="<<endl;
for(auto a:v1)
{
cout<<a<<endl;
}
v1.clear();
v1.reserve(10);
v1.push_back("word_1");
v1.push_back("word_2");
v1.push_back("word_3");
cout<<endl<<"多线程操作迭代器"<<endl;
thread th1(func1);
thread th2(func2);
th1.join();
th2.join();
cout<<"===== show ====="<<endl;
for(auto a:v1)
{
cout<<a<<endl;
}
//多线程添加数据之后的数据量
cout<<v1.capacity()<<"|"<<v1.size()<<endl;
}
int main()
{
cout<<"===== begin ====="<<endl;
// test_1();
// test_2();
test_3();
test_4();
test_5();
test_6();
cout<<"===== end ====="<<endl;
return 0;
}
/*
* 多线程容器接口测试
*
===== begin =====
===== queue_th =====
=====
11
12
13
14
15
=====
s11
s22
s33
s44
s55
s66
s77
=====
600
=====
600
600
600
swap front: 0
swap after: 600
===== vector_th =====
5
5
5
=====
v1
v2
v3
v4
v5
=====
v1
v2
v3
v4
v5
=====
v3
v4
=====
capacity: 8
size: 6
=====
v0
v1
v2
v3
v4
v5
=====
30000
===== map_th =====
1|10
2|20
3|30
4|40
5|50
6|60
7|70
7
7
7
0
4
904
2700
== 迭代器易位测试 ==
10|3
单线程操作迭代器
对比点: word_1
对比点: word_2
===== show =====
word_1
add word
word_2
word_3
多线程操作迭代器
对比点: word_1
对比点: add word
===== show =====
word_1
add word
word_2
word_3
10|4
===== end =====
*/