我有两个线程,一个在 tbb::concurrent_hash_map 上执行 find(),另一个在不执行任何插入或删除的情况下遍历此映射。奇怪的是,如果不执行find(),迭代遍历是正常的,但是当执行find()时,使用HashMap::iterator迭代得到的数据却少了。为什么会这样?
为什么执行find()时通过HashMap::iterator迭代得到的数据少了?
我添加了一个测试示例,包括两段代码。一个是我封装tbb::concurrent_hash_map的地方,另一个是测试示例。结果如下:
writeTime=0.370875
------------finish write---------------
------ hashMap size = 3174014
cnt size=3210251
error
-----readTime=2.22228
代码:
#include<map>
#include<string>
#include<vector>
#include<fstream>
#include<iostream>
#include <omp.h>
#include <tbb/concurrent_hash_map.h>
template <typename KeyType, typename ValueType>
class ConcurrentHashMap {
private:
typedef tbb::concurrent_hash_map<KeyType, ValueType> HashMap;
typedef typename HashMap::const_accessor HashMapConstAccessor;
typedef typename HashMap::accessor HashMapAccessor;
typedef typename HashMap::iterator HashMapIterator;
typedef typename HashMap::value_type HashMapValuePair;
public:
ConcurrentHashMap (ValueType default_value) : DEFAULT_VALUE(default_value) {
}
size_t size() {
return hashMap.size();
}
bool insert(const KeyType& key, const ValueType& value) {
HashMapAccessor accessor;
bool inserted = hashMap.insert(accessor, key);
if (inserted) {
accessor->second = value;
}
return inserted;
}
bool erase(const KeyType& key) {
return hashMap.erase(key);
}
bool find(const KeyType& key, ValueType& value) {
HashMapConstAccessor accessor;
if (hashMap.find(accessor, key)) {
value = accessor->second;
return true;
}
value = DEFAULT_VALUE;
return false;
}
void clear() {
hashMap.clear();
}
const ValueType& operator[](const KeyType& key) const {
HashMapConstAccessor accessor;
hashMap.find(accessor, key);
if (hashMap.find(accessor, key)) {
return accessor->second;
}
// accessor->second = DEFAULT_VALUE;
return DEFAULT_VALUE;
}
HashMapIterator begin() {
return hashMap.begin();
}
HashMapIterator end() {
return hashMap.end();
}
private:
HashMap hashMap;
ValueType DEFAULT_VALUE;
};
#include<map>
#include<string>
#include<vector>
#include<fstream>
#include<iostream>
#include <omp.h>
#include <tbb/tbb.h>
#include "./ConcurrentHashMap.h"
#include "./ConcurrentUnorderMap.h"
using namespace std;
class A;
using HashMap = ConcurrentHashMap<int, A*>;
// using HashMap = ConcurrentUnorderedMap<int, A*>;
class A {
public:
A(int _a, int _b): a(_a), b(_b) {
}
void sub () {
}
int a = 1;
int b = 0;;
};
void test(int N, HashMap& hashMap) {
int thread_num = 16;
std::thread writer(
[&] () {
auto writeStartTime = std::chrono::high_resolution_clock::now();
#pragma omp parallel for num_threads(thread_num)
for (int i = 0; i < N; i++) {
hashMap.insert(i, new A(1, i));
}
auto writeEndTime = std::chrono::high_resolution_clock::now();
double writeTime = std::chrono::duration<double>(writeEndTime
- writeStartTime).count();
std::cout << "writeTime=" << writeTime << std::endl;
}
);
writer.join();
}
int main () {
// cmd: g++ test_con_hashmap.cpp -fopenmp -ltbb && ./a.out
int N = 3174014;
std::nullptr_t NULLPOINTER = nullptr;
HashMap hashMap(NULLPOINTER);
test(N, hashMap);
cout << "------------finish write---------------" << std::endl;
size_t hashmap_size = hashMap.size();
cout << "\n------ hashMap size = " << hashmap_size << endl;
{
int thread_num = 32;
std::thread reader(
[&] () {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
auto readStartTime = std::chrono::high_resolution_clock::now();
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(0, N - 1);
for (int i = 0; i < 10; i++) {
#pragma omp parallel for num_threads(thread_num)
for (int i = 0; i < N; i++) {
A* value;
int randomKey = dis(gen);
if(hashMap.find(randomKey, value)){
}
}
}
auto readEndTime = std::chrono::high_resolution_clock::now();
double readTime = std::chrono::duration<double>(readEndTime
- readStartTime).count();
std::cout << "-----readTime=" << readTime << std::endl;
}
);
size_t cnt = 0;
for(auto iterator1 = hashMap.begin();
iterator1 != hashMap.end(); ++iterator1 ){
cnt++;
}
std::cout << " cnt=" << cnt << std::endl;
if (cnt != hashmap_size) {
std::cout << " error" << std::endl;
}
reader.join();
}
hashMap.clear();
return 0;
}