confusion over using upgradable lock on std::map's find/insert - c++

Consider a thread-safe getter method in its,relatively, simplest form:
std::map<std::string, boost::shared_ptr<AAA> > repo;
AAA & get(const std::string &key)
{
boost::upgrade_lock<boost::shared_mutex> lock(repoMutex);
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
boost::shared_ptr<AAA> t(new AAA(key));
repo.insert(std::make_pair(key,t));
return *t;
}
return *it->second;
}
in above, I use a shared(upgradeable) lock to protect a find operation, and upgrade to unique lock only if I need to insert a key/value. So far so good?
What I imagine is the following(please let me know if in any step my concept is wrong):
Two threads enter the method
Both are allowed to run repo.find() for the same key at the same time(and the key doesn't exist).
Both of them fail.as the key doesn't exist .
first thread gets exclusive access by entering the upgraded area, while the second thread waiting to enter upgraded area.
first thread finishes its job of creating a new entry for key and then
walks off.
second thread enters and overwrites the key/value inserted by the first thread.(which is not what anybody wants)
How do we solve this issue? thanks

In short, there's almost nothing wrong with your current solution.
First of all, the second thread won't overwrite the data written by the first one, because map::insert() inserts only new keys. You only have to check if insert really inserted the element and return corresponding value.
The only concern is possible unwanted creation of t for nothing. In this case you can add another check after locking:
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
if (repo.find(key) == repo.end() {
...
}
}
But you should profile your code to see if this gives you any advantage.
Also, you can utilize map::insert() with hint to avoid double searching for the key:
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
it = repo.lower_bound(key);
if (it->first != key)
boost::shared_ptr<AAA> t(new AAA(key));
repo.insert(it, std::make_pair(key,t));
return *t;
} else {
return *it->second;
}
}

Related

compiler doesn't finish process

I have a multimap which key is short and value is the other multimap
std::multimap<short,std::multimap<short,short>> multimap
now I want to do it`
std::multimap<short,short> &a=multimap.find(0)->second;
std::pair<short,short> z={1,2};
a.insert(z);
It compiles fine. But when I run it it just stops and doesn't finish the process, It even doesn't throw any runtimeerror. Have any ideas? Thanks in advice.
Having
std::multimap<short,std::multimap<short,short>> multimap
...
std::multimap<short,short> &a=multimap.find(0)->second;
std::pair<short,short> z={1,2};
a.insert(z);
If find returns multimap::end that one shall not be dereferenced, but you do and get a reference to second, the behavior is undefined when later to use that reference to insert.
So of course check if find succes, like
std::multimap<short,std::multimap<short,short>> multimap;
std::multimap<short,std::multimap<short,short>>::iterator it = multimap.find(0);
if (it == multimap.end()) {
...
}
else {
std::multimap<short,short> &a = it->second;
std::pair<short,short> z={1,2};
a.insert(z);
}
Out of that your title "compiler doesn't finish process" is not very clear, the execution is not the one you expect, but the compiler does not run the process
If multimap does not have an item with key 0, then multimap.find(0) returns an iterator that is not dereferenceable. Always check the return values of such calls before dereferencing the iterator.
auto iter = multimap.find(0);
if ( iter != multimap.end() )
{
std::multimap<short,short> &a = iter->second;
std::pair<short,short> z={1,2};
a.insert(z);
}
else
{
// Decide what to do
}

TBB concurrent unordered map causes segfault

I need to implement a huge hash table which supports multiple threads to insert and get at the same time. The keys are int and the second elements are vectors of object T.
class T {
//class definitions here
}
Currently the implementation is helped with tbb::concurrent_unordered_map. On the documentation it seems to allow insertion and traversal at the same time. However, running with multiple pthreads will lead to segmentation fault although sequential test is perfectly fine. Note that there is definitely no erase or pop operations, i.e. the hash table is only allowed to grow.
std::vector<T*> get(int key) {
//Note that the hash table hashTable is shared by multiple threads
tbb::concurrent_unordered_map<int, std::vector<T*>>::iterator it = hashTable.find(key);
if (it != hashTable.end())
return it->second;
else {
std::vector<T*> newvector;
return newvector;
}
}
void insert(int key, T *t) {
tbb::concurrent_unordered_map<int, std::vector<T*>>::iterator it = hashTable.find(key);
if (it != hashTable.end())
it->second.push_back(t);
else {
std::vector<T*> newTs;
newTs.push_back(t);
hashTable.insert(it, makepair(key, newTs));
}
}
To debug what happened, I first changed std::vector to tbb::concurrent_vector, and then modify the function get() and insert() as follows.
std::vector<T*> get_test(int key) {
std::vector<T*> test;
//Note that the hash table hashTable is shared by multiple threads
tbb::concurrent_unordered_map<int, tbb::concurrent_vector<T*>>::iterator it = hashTable.find(key);
if (it != hashTable.end())
test.insert(test.end(), it->second.begin(), it->second.end());
for (T* _t : test)
if (!_t)
printf("Bug happens here!\n"); //Segfault is originated here because a NULL is returned in the vector
return test;
}
void insert_test(int key, T *t) {
//Here t is guaranteed to be not NULL
if(!t)
std::terminate();
tbb::concurrent_unordered_map<int, tbb::concurrent_vector<T*>>::iterator it = hashTable.find(key);
if (it != hashTable.end())
it->second.push_back(t);
else {
std::vector<T*> newTs;
newTs.push_back(t);
hashTable.insert(it, makepair(key, newTs));
}
}
Now we can see the reason that the parallel program crashes is some NULL pointer is returned in get_test() function. Recall that in insert_test() function NULL is never inserted as the second elements.
The following are the questions to ask.
(1) I read from somewhere that concurrent insertion in tbb::concurrent_unordered_map may cause some of the insertion attempt failed and then the temp objects is destroyed. Is this the reason that NULL is observed in get_test() function?
(2) Can TBB really allow insertion and traversal at the same time? This means while some threads are inserting, the others might call get() at the same time.
(3) Is there any better implementation, i.e. better concurrent hash table that support concurrent insert and read?
As #for_stack suggested, I have verified the second elements are concurrent_vectors and the entire program is runnable. A further test is conducted as follows:
tbb::concurrent_vector<T*> get_test(int key) {
tbb::concurrent_vector<T*> test;
//Note that the hash table hashTable is shared by multiple threads
tbb::concurrent_unordered_map<int, tbb::concurrent_vector<T*>>::iterator it = hashTable.find(key);
if (it != hashTable.end())
test = it->second;
int i = 0;
for (T* _t : test)
if (!_t)
i++;
if (i > 0)
printf("%d of %lu Ts are NULL\n", i, test.size()); //Segfault is originated here because a NULL is returned in the vector
return test;
}
void insert_test(int key, T *t) {
//Here t is guaranteed to be not NULL
if(!t)
std::terminate();
tbb::concurrent_unordered_map<int, tbb::concurrent_vector<T*>>::iterator it = hashTable.find(key);
if (it != hashTable.end())
it->second.push_back(t);
else {
tbb::concurrent_vector<T*> newTs;
newTs.push_back(t);
hashTable.insert(it, make_pair(key, newTs));
}
}
The output is
1 of 2 Ts are NULL
This means not all objects (T) returned in get() are NULL.
Again the sequential (or even 1 thread) running is fine.
TBB CAN support concurrent insertion and traversal for concurrent_xxx containers. However, your original code has race conditions:
std::vector<T*> get(int key) {
// other code
return it->second; # race condition 1
// other code
}
The get function try to return a copy of vector<T*> (read), while other threads might call insert to modify the vector<T*> (write).
void insert(int key, T *t) {
// other code
it->second.push_back(t); # race condition 2
// other code
}
The insert function try to modify the vector<T*> with no lock guard. If there are several threads call insert at the same time (multiple write), OOPS!
concurrent_unordered_map only has safe guarantee for container operations, while it has no guarantee for operations on the mapped_value. You have to do it yourself.
Just as what you've tried, you can replace the vector<T*> with concurrent_vector<T*>. However, the new code you posted doesn't compile, you have to modify the implementation of insert_test:
void insert_test(int key, T *t) {
//Here t is guaranteed to be not NULL
if(!t)
std::terminate();
tbb::concurrent_unordered_map<int, tbb::concurrent_vector<T*>>::iterator it = hashTable.find(key);
if (it != hashTable.end())
it->second.push_back(t);
else {
// std::vector<T*> newTs; # this is wrong!
tbb::concurrent_vector<T*> newTs;
newTs.push_back(t);
hashTable.insert(it, make_pair(key, newTs)); // it should be make_pair not makepair
}
}
"TBB CAN support concurrent insertion and traversal for concurrent_xxx containers." - not exactly. Traversal is a tricky thing when there is no memory reclamation support like in TBB and concurrent erasure is supported by a container (concurrent_hash_map). However, concurrent_unordered_map does not support thread-safe erase() and thus thread-safe traversal is supported.
#Anton my friend, the concurrent_unordered containers do support concurrent traversal and insertion; they're implemented as skip-lists. In the non-multi case the result of the pointer swing is tested, and if it fails the search is started again from the point of insertion.
Now C++ may have changed in the last few weeks since I worked at Intel, but I think there are serious bugs in the original code:
if (it != hashTable.end())
return it->second; // return a copy???
else {
std::vector<T*> newvector; // this is stack-allocated
return newvector; // return a copy??
}
The return value is vector, not reference or pointer to vector, so you are going to get copies of the current contents as return values, and inserting into the copy will not change any vector that is in the set. Maybe fix that, and make sure there is no asynchronous reference to a vector, and then look for remaining bugs.

find a element in a vector from one of its arguments

How would i find a element in a vector from one of its arguments set with emplace_back
Trying to detach thread then delete it from vector.
std::vector<std::thread> vTimerThreads;
void SetTimer(UINT ID, DWORD dwMilliseconds)
{
// timerThreadProc is my thread that handles my timers
vTimerThreads.emplace_back(timerThreadProc, ID, dwMilliseconds);
}
void DeleteTimer(UINT ID)
{
//Find thread by ID?
// thread.detach();
// then delete
}
SetTimer(TIMER1, 5000);
std::find_if sounds like what you want if you're just going to remove based on id.
void DeleteTimer(std::thread::id ID)
{
std::vector<std::thread>::iterator itr = std::find_if(vTimerThreads.begin(), vTimerThreads.end(), [&](const std::thread& t) { return t.get_id() == ID; });
if( itr != vTimerThreads.end() )
vTimerThreads.erase(itr);
}
I've used a lambda here but it's not necessary.
If you're thinking of using a large number of threads, maybe a different data structure would suit you better. Have you considered an std::set for faster searching? Perhaps even a map or hash_map would be good for you, where the id is the key? You could put the threads into these containers with move semantics instead of emplace_back without having copying (as I suspect is motivating you to use emplace).
Check out the std::algorithm library though, there's some great stuff in there
EDIT:
I see in one of the comments OP says that ID is not in fact the thread id. Unless we can get clarification on what member of T for std::vector<T> we are meant to be searching on, an explicit solution cannot be provided.
As long as I'm doing an edit, here's some code for adding threads to a std::map without copying. With the following code it'll be trivial to find an element by std::thread::id or whatever else you want to use as a key and then delete it.
std::map<std::thread::id, std::thread> mapTimerThreads;
void AddNewThreadToMap()
{
std::thread t;
mapTimerThreads[t.get_id()] = std::move(t);
}
If you want to do a simple linear search (which makes sense if the number of threads is not large) you can just do
void DeleteTimer(UINT ID)
{
for(int i = 0; i < vTimerThreads.size(); i++)
if(vTimerThreads[i].get_id() == ID)
{
vTimerThreads.erase(vTimerThreads.begin()+i);
break;
}
}
If your number of threads is large, arbitrary deletion like this is expensive - you might want to consider something like forward_list instead of vector in that case.

VS2013 C++: Map - Unhandled Exception, Out of Range

I'm trying to create a function that keeps track of recently used addresses, using a vector of maps for each index. Each time the address (used as the map key) is found, it would update the key member variable value. If its not a mapped value in the table, it will add it. That way I can keep track of older vs. newer addresses. Initially I tried to code it in the following manner:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
auto search = table.at(index).find(address);
if(it != table.at(index).end())
{
table[index][address] = ++key;
}
else
{
table.at(index).insert(make_pair(address, ++key));
}
}
However, every time I go to test my function, VS2013 always throws an unhandled exception error informing me that the Unhandled exception was thrown because std::out_of_range when it gets to the auto search line. I figured the error was thrown because the map starts off initially empty, and there are no maps available for it to search through for any addresses. So then I modified it to determine first if the table is empty, if so insert the first pair, otherwise if its not, search the table for the address value, and update the key:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
if(table.at(index).empty())
{
table.at(index).insert(make_pair(address, key));
}
else
{
auto search = table.at(index).find(address);
if(it != table.at(index).end())
{
table[index][address] = ++key;
}
else
{
table.at(index).insert(make_pair(address, ++key));
}
}
}
But then the same exception occurs at the if(table.at(index).empty()) line. Then I scaled it down, just to see if I could just simply capture and store any maps at all:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
table.at(index).insert(make_pair(address, ++key));
}
And that generates the same unhandled exception also at table.at(index).insert(make_pair(address, ++key)).
Not only that but I've tried determining if the table.at(index) == NULL or nullptr or 0. Looked for alternative means of adding the map pairs to the vector, instead of using insert. Unfortunately, the options I was looking at don't exist for map (i.e. assign or push_back). I also looked into implementing a try-catch statement, but wasn't exactly sure on how to code it, especially with the "throw" keyword.
I have no idea what could be causing this issue. Does anyone have any suggestions on what could be the problem? Or what I'm doing wrong? Maybe my program doesn't like my vector of maps possibly?
Thank you!

C++ map iteration with deletion

I couldn't find an instance of how to do this, so I was hoping someone could help me out. I have a map defined in a class as follows:
std::map<std::string, TranslationFinished> translationEvents;
TranslationFinished is a boost::function. I have a method as part of my class that iterates through this map, calling each of the functions like so:
void BaseSprite::DispatchTranslationEvents()
{
for(auto it = translationEvents.begin(); it != translationEvents.end(); ++it)
{
it->second(this);
}
}
However it's possible for a function called by it->second(this); to remove an element from the translationEvents map (usually itself) using the following function:
bool BaseSprite::RemoveTranslationEvent(const std::string &index)
{
bool removed = false;
auto it = translationEvents.find(index);
if (it != translationEvents.end())
{
translationEvents.erase(it);
removed = true;
}
return removed;
}
doing this causes a debug assertion fail when the DispatchTranslationEvents() tries to increment the iterator. Is there a way to iterate through a map safely with the possibility that a function call during the iteration may remove an element from the map?
Thanks in advance
EDIT: Accidently C/Pd the wrong Remove Event code. Fixed now.
map::erase invalidates the iterator being deleted (obviously), but not the rest of the map.
This means that:
if you delete any element other than the current one, you're safe, and
if you delete the current element, you must first get the next iterator, so you can continue iterating from that (that's why the erase function for most containers return the next iterator). std::map's doesn't, so you have to do this manually)
Assuming you only ever delete the current element, then you could simply rewrite the loop like this:
for(auto it = translationEvents.begin(); it != translationEvents.end();)
{
auto next = it;
++next; // get the next element
it->second(this); // process (and maybe delete) the current element
it = next; // skip to the next element
}
Otherwise (if the function may delete any element) it may get a bit more complicated.
Generally speaking it is frowned upon to modify the collection during iteration. Many collections invalidate the iterator when the collection is modified, including many of the containers in C# (I know you're in C++). You can create a vector of events you want removed during the iteration and then remove them afterwards.
After reading all other answers, I am at an advantage here... But here it goes.
However it's possible for a function called by it->second(this); to remove an element from the translationEvents map (usually itself)
If this is true, that is, a callback can remove any element from the container, you cannot possibly resolve this issue from the loop itself.
Deleting the current callback
In the simpler case where the callback can only remove itself, you can use different approaches:
// [1] Let the callback actually remove itself
for ( iterator it = next = m.begin(); it != m.end(); it = next ) {
++next;
it->second(this);
}
// [2] Have the callback tell us whether we should remove it
for ( iterator it = m.begin(); it != m.end(); ) {
if ( !it->second(this) ) { // false means "remove me"
m.erase( it++ );
} else {
++it;
}
}
Among these two options, I would clearly prefer [2], as you are decoupling the callback from the implementation of the handler. That is, the callback in [2] knows nothing at all about the container in which it is held. [1] has a higher coupling (the callback knows about the container) and is harder to reason about as the container is changed from multiple places in code. Some time later you might even look back at the code, think that it is a weird loop (not remembering that the callback removes itself) and refactor it into something more sensible as for ( auto it = m.begin(), end = m.end(); it != end; ++it ) it->second(this);
Deleting other callbacks
For the more complex problem of can remove any other callback, it all depends on the compromises that you can make. In the simple case, where it only removes other callbacks after the complete iteration, you can provide a separate member function that will keep the elements to remove, and then remove them all at once after the loop completes:
void removeElement( std::string const & name ) {
to_remove.push_back(name);
}
...
for ( iterator it = m.begin(); it != m.end(); ++it ) {
it->second( this ); // callback will possibly add the element to remove
}
// actually remove
for ( auto it = to_remove.begin(); it != to_begin.end(); ++it ) {
m.erase( *it );
}
If removal of the elements need to be immediate (i.e. they should not be called even in this iteration if they have not yet been called), then you can modify that approach by checking whether it was marked for deletion before executing the call. The mark can be done in two ways, the generic of which would be changing the value type in the container to be a pair<bool,T>, where the bool indicates whether it is alive or not. If, as in this case, the contained object can be changed you could just do that:
void removeElement( std::string const & name ) {
auto it = m.find( name ); // add error checking...
it->second = TranslationFinished(); // empty functor
}
...
for ( auto it = m.begin(); it != m.end(); ++it ) {
if ( !it->second.empty() )
it->second(this);
}
for ( auto it = m.begin(); it != m.end(); ) { // [3]
if ( it->second.empty() )
m.erase( it++ );
else
++it;
}
Note that since a callback can remove any element in the container, you cannot erase as you go, as the current callback could remove an already visited iterator. Then again, you might not care about leaving the empty functors for a while, so it might be ok just to ignore it and perform the erase as you go. Elements already visited that are marked for removal will be cleared in the next pass.
My solution is to first create a temporary container, and swap it with the original one. Then you can iterator through the temporary container and insert the ones you want to keep to the original container.
void BaseSprite::DispatchTranslationEvents()
{
typedef std::map<std::string, TranslationFinished> container_t;
container_t tempEvents;
tempEvents.swap(translationEvents);
for(auto it = tempEvents.begin(); it != tempEvents.end(); ++it)
{
if (true == it->second(this))
translationEvents.insert(it);
}
}
And the TranslationFinished functions should return true if it want to be keeped and return false to get removed.
bool BaseSprite::RemoveTranslationEvent(const std::string &index)
{
bool keep = false;
return keep;
}
There should be a way for you to erase a element during your iteration, maybe a little tricky.
for(auto it = translationEvents.begin(); it != translationEvents.end();)
{
//remove the "erase" logic from second call
it->second(this);
//do erase and increase the iterator here, NOTE: ++ action is very important
translationEvents.erase(it++);
}
The iterator will be invalid once the element is removed, so you can not use that iterator to do increase action anymore after you remove it. However, remove an element will not affect other element in map implementation, IIRC. So suffix ++ will copy the iter first and increase the iterator right after that, then return the copy value, which means iterator is increased before erase action, this should be safe for you requirement.
You could defer the removal until the dispatch loop:
typedef boost::function< some stuff > TranslationFunc;
bool BaseSprite::RemoveTranslationEvent(const std::string &index)
{
bool removed = false;
auto it = translationEvents.find(index);
if (it != translationEvents.end())
{
it->second = TranslationFunc(); // a null function indicates invalid event for later
removed = true;
}
return removed;
}
protect against invoking an invalid event in the loop itself, and cleanup any "removed" events:
void BaseSprite::DispatchTranslationEvents()
{
for(auto it = translationEvents.begin(); it != translationEvents.end();)
{
// here we invoke the event if it exists
if(!it->second.empty())
{
it->second(this);
}
// if the event reset itself in the map, then we can cleanup
if(it->second.empty())
{
translationEvents.erase(it++); // post increment saves hassles
}
else
{
++it;
}
}
}
one obvious caveat is if an event is iterated over, and then later on deleted, it will not get a chance to be iterated over again to be deleted during the current dispatch loop.
this means the actual deletion of that event will be deferred until the next time the dispatch loop is run.
The problem is ++it follows the possible erasure. Would this work for you?
void BaseSprite::DispatchTranslationEvents()
{
for(auto it = translationEvents.begin(), next = it;
it != translationEvents.end(); it = next)
{
next=it;
++next;
it->second(this);
}
}