Crash using concurrent_unordered_map - c++

I've got a concurrent_unordered_map. I use the insert function (and no other) to try to insert into the map concurrently. However, many times, this crashes deep in the insert function internals. Here is some code:
class ModuleBase {
public:
virtual Wide::Parser::AST* GetAST() = 0;
virtual ~ModuleBase() {}
};
struct ModuleContents {
ModuleContents() {}
ModuleContents(ModuleContents&& other)
: access(other.access)
, base(std::move(other.base)) {}
Accessibility access;
std::unique_ptr<ModuleBase> base;
};
class Module : public ModuleBase {
public:
// Follows Single Static Assignment form. Once it's been written, do not write again.
Concurrency::samples::concurrent_unordered_map<Unicode::String, ModuleContents> contents;
Wide::Parser::AST* GetAST() { return AST; }
Wide::Parser::NamespaceAST* AST;
};
This is the function I use to actually insert into the map. There is more but it doesn't touch the map, only uses the return value of insert.
void CollateModule(Parser::NamespaceAST* module, Module& root, Accessibility access_level) {
// Build the new module, then try to insert it. If it comes back as existing, then we discard. Else, it was inserted and we can process.
Module* new_module = nullptr;
ModuleContents m;
{
if (module->dynamic) {
auto dyn_mod = MakeUnique<DynamicModule>();
dyn_mod->libname = module->libname->contents;
new_module = dyn_mod.get();
m.base = std::move(dyn_mod);
} else {
auto mod = MakeUnique<Module>();
new_module = mod.get();
m.base = std::move(mod);
}
new_module->AST = module;
m.access = access_level;
}
auto result = root.contents.insert(std::make_pair(module->name->name, std::move(m)));
This is the root function. It is called in parallel from many threads on different inputs, but with the same root.
void Collater::Context::operator()(Wide::Parser::NamespaceAST* input, Module& root) {
std::for_each(input->contents.begin(), input->contents.end(), [&](Wide::Parser::AST* ptr) {
if (auto mod_ptr = dynamic_cast<Wide::Parser::NamespaceAST*>(ptr)) {
CollateModule(mod_ptr, root, Accessibility::Public);
}
});
}
I'm not entirely sure wtf is going on. I've got one bit of shared state, and I only ever access it atomically, so why is my code dying?
Edit: This is actually completely my own fault. The crash was in the insert line, which I assumed to be the problem- but it wasn't. It wasn't related to the concurrency at all. I tested the return value of result the wrong way around- i.e., true for value existed, false for value did not exist, whereas the Standard defines true for insertion succeeded- i.e., value did not exist. This mucked up the memory management significantly, causing a crash- although exactly how it led to a crash in the unordered_map code, I don't know. Once I inserted the correct negation, it worked flawlessly. This was revealed because I didn't properly test the single-threaded version before jumping the concurrent fence.

One possibility is that you are crashing because of some problem with move semantics. Is the crash caused by a null pointer dereference? That would happen if you inadvertently accessed an object (e.g., ModuleContents) after it's been moved.
It's also possible that the crash is the result of a concurrency bug. The concurrent_unordered_map is thread safe in the sense that insertion and retrieval are atomic. However, whatever you are storing inside it is not automatically protected. So if multiple threads retrieve the same ModuleContents object, they will share the AST tree that's inside a Module. I'm not sure which references are modifiable, since I don't see any const pointers or references. Anything that is shared and modifiable must be protected by some synchronization mechanism (for instance, locks).

Related

Most efficient paradigm for checking if a key exists in a c++ std::unordered_map?

I am relatively new to modern c++ and working with a foreign code base. There is a function that takes a std::unordered_map and checks to see if a key is present in the map. The code is roughly as follows
uint32_t getId(std::unordered_map<uint32_t, uint32_t> &myMap, uint32_t id)
{
if(myMap.contains(id))
{
return myMap.at(id);
}
else
{
std::cerr << "\n\n\nOut of Range error for map: "<< id << "\t not found" << std::flush;
exit(74);
}
}
It seems like calling contains() followed by at() is inefficient since it requires a double lookup. So, my question is, what is the most efficient way to accomplish this? I also have a followup question: assuming the map is fairly large (~60k elements) and this method gets called frequently how problematic is the above approach?
After some searching, it seems like the following paradigms are more efficient than the above, but I am not sure which would be best.
Calling myMap.at() inside of a try-catch construct
Pros: at automatically throws an error if the key does not exist
Cons: try-catch is apparently fairly costly and also constrains what the optimizer can do with the code
Use find
Pros: One call, no try-catch overhead
Cons: Involves using an iterator; more overhead than just returning the value
auto findit = myMap.find(id);
if(findit == myMap.end())
{
//error message;
exit(74);
}
else
{
return findit->first;
}
You can do
// stuff before
{
auto findit = myMap.find(id);
if ( findit != myMap.end() ) {
return findit->first;
} else {
exit(74);
}
}
// stuff after
or with the new C++17 init statement syntax
// stuff before
if ( auto findit = myMap.find(id); findit != myMap.end() ) {
return findit->first;
} else {
exit(74);
}
// stuff after
Both define the iterator reference only in local scope. As the interator use is most definitively optimized away, I would go with it. Doing a second hash calculation will be slower almost for sure.
Also note that findit->first returns the key not the value. I was not sure what you expect the code to do, but one of the code snippets in the question returns the value, while the other one returns the key
In case you don't get enough speedup within only removing the extra lookup operation and if there are millions of calls to getId in a multi-threaded program, then you can use an N-way map to be able to parallelize the id-checks:
template<int N>
class NwayMap
{
public:
NwayMap(uint32_t hintMaxSize = 60000)
{
// hint about max size to optimize initial allocations
for(int i=0;i<N;i++)
shard[i].reserve(hintMaxSize/N);
}
void addIdValuePairThreadSafe(const uint32_t id, const uint32_t val)
{
// select shard
const uint32_t selected = id%N; // can do id&(N-1) for power-of-2 N value
std::lock_guard<std::mutex> lg(mut[selected]);
auto it = shard[selected].find(id);
if(it==shard[selected].end())
{
shard[selected].emplace(id,val);
}
else
{
// already added, update?
}
}
uint32_t getIdMultiThreadSafe(const uint32_t id)
{
// select shard
const uint32_t selected = id%N; // can do id&(N-1) for power-of-2 N value
// lock only the selected shard, others can work in parallel
std::lock_guard<std::mutex> lg(mut[selected]);
auto it = shard[selected].find(id);
// we expect it to be found, so get it quicker
// without going "else"
if(it!=shard[selected].end())
{
return it->second;
}
else
{
exit(74);
}
}
private:
std::unordered_map<uint32_t, uint32_t> shard[N];
std::mutex mut[N];
};
Pros:
if you serve each shard's getId from their own CPU threads, then you benefit from N*L1 cache size.
even within single thread use case, you can still interleave multiple id-check operations and benefit from instruction-level-parallelism because checking id 0 would have different independent code path than checking id 1 and CPU could do out-of-order execution on them (if pipeline is long enough)
Cons:
if a lot of checks from different threads collide, their operations are serialized and the locking mechanism causes extra latency
when id values are mostly strided, the parallelization is not efficient due to unbalanced emplacement
Calling myMap.at() inside of a try-catch construct
Pros: at automatically throws an error if the key does not exist
Cons: try-catch is apparently fairly costly and also constrains what the optimizer can do with the code
Your implementation of getId terminates application, so who cares about exception overheads?
Please note that most compilers (AFAIK all) implement C++ exceptions to have zero cost when exception is not thrown. Problem appears when stack is unwinded when exception is thrown and matching exception handler. I read somewhere that penalty when exception is thrown is x40 comparing to case when stack is unwinded by simple returns (with possible error codes).
Since you want to just terminate application then this overhead is negligible.

c++, dealing with exceptions from constructors

I have a class which is loaded from an external file, so ideally I would want its constructor to load from a given path if the load fails, I will want to throw an error if the file is not found/not readable (Throwing errors from constructors is not a horrible idea, see ISO's FAQ).
There is a problem with this though, I want to handle errors myself in some controlled manner, and I want to do that immediately, so I need to put a try-catch statement around the constructor for this object ... and if I do that, the object is not declared outside the try statement, i.e.:
//in my_class.hpp
class my_class
{
...
public:
my_class(string path);//Throws file not found, or other error error
...
};
//anywhere my_class is needed
try
{
my_class my_object(string);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
//Problem... now my_object doesn't exist anymore
I have tried a number of ways of getting around it, but I don't really like any of them:
Firstly, I could use a pointer to my_class instead of the class itself:
my_class* my_pointer;
try
{
my_class my_pointer = new my_class(string);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
The problem is that the instance of this object doesn't always end up in the same object which created it, so deleting all pointers correctly would be easy to do wrong, and besides, I personally think it is ugly to have some objects be pointers to objects, and have most others be "regular objects".
Secondly, I could use a vector with only one element in much the same way:
std::vector<my_class> single_vector;
try
{
single_vector.push_back(my_class(string));
single_vector.shrink_to_fit();
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
I don't like the idea of having a lot of single-element vectors though.
Thirdly, I can create an empty faux constructor and use another loading function, i.e.
//in my_class.hpp
class my_class
{
...
public:
my_class() {}// Faux constructor which does nothing
void load(string path);//All the code in the constructor has been moved here
...
};
//anywhere my_class is needed
my_class my_object
try
{
my_object.load(path);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
This works, but largely defeats the purpose of having a constructor, so I don't really like this either.
So my question is, which of these methods for constructing an object, which may throw errors in the constructor, is the best (or least bad)? and are there better ways of doing this?
Edit: Why don't you just use the object within the try-statement
Because the object may need to be created as the program is first started, and stopped much later. In the most extreme case (which I do actually need in this case also) that would essentially be:
int main()
{
try
{
//... things which might fail
//A few hundred lines of code
}
catch(/*whaveter*/)
{
}
}
I think this makes my code hard to read since the catch statement will be very far from where things actually went wrong.
One possibility is to wrap the construction and error handling in a function, returning the constructed object. Example :
#include <string>
class my_class {
public:
my_class(std::string path);
};
my_class make_my_object(std::string path)
{
try {
return {std::move(path)};
}
catch(...) {
// Handle however you want
}
}
int main()
{
auto my_object = make_my_object("this path doesn't exist");
}
But beware that the example is incomplete because it isn't clear what you intend to do when construction fails. The catch block has to either return something, throw or terminate.
If you could return a different instance, one with a "bad" or "default" state, you could have just initialized your instance to that state in my_class(std::string path) when it was determined the path is invalid. So in that case, the try/catch block is not needed.
If you rethrow the exception, then there is no point in catching it in the first place. In that case, the try/catch block is also not needed, unless you want to do a bit of extra work, like logging.
If you want to terminate, you can just let the exception go uncaught. Again, in that case, the try/catch block is not needed.
The real solution here is probably to not use a try/catch block at all, unless there is actually error handling you can do that shouldn't be implemented as part of my_class which isn't made apparent in the question (maybe a fallback path?).
and if I do that, the object is not declared outside the try statement
I have tried a number of ways of getting around it
That doesn't need to be a problem. There's not necessarily need to get around it. Simply use the object within the try statement.
If you really cannot have the try block around the entire lifetime, then this is a use case for std::optional:
std::optional<my_class> maybe_my_object;
try {
maybe_my_object.emplace(string);
} catch(...) {}
The problem is that the instance of this object doesn't always end up in the same object which created it, so deleting all pointers correctly would be easy to do wrong,
A pointer returned by new is correct to delete. In the error case, simply set the pointer to null and there would be no problem. That said, use a smart pointer instead for dynamic allocation, if you were to use this approach.
single_vector.push_back(my_class(string));
single_vector.shrink_to_fit();
Don't push and shrink when you know the number of objects that are going to be in the vector. Use reserve instead if you were to use this approach.
The object creation can fail because a resource is unavailable. It's not the creation which fails; it is a prerequisite which is not fulfilled.
Consequently, separate these two concerns: First obtain all resources and then, if that succeeded, create the object with these resources and use it. The object creation as such in this design cannot fail, the constructor is nothrow; it is trivial boilerplate code (copy data etc.). If, on the other hand, resource acquisition failed, object creation and object use are both skipped: Your problem with existing but unusable objects is gone.
Responding to your edit about try/catch comprising the entire program: Exceptions as error indicators are better suited for things which are done in many places at various times in a program because they guarantee error handling (by default through an abort) while separating it from the normal control flow. This is impossible to do with classic return value examination, which leaves us with a choice between unreadable or unreliable programs.
But if you have long-lived objects which are created only rarely (in your example: only at startup) you don't need exceptions. As you said, constructor exceptions guarantee that only properly initialized objects can be used. But if such an object is only created at startup this danger is low. You check for success one way or another and exit the program which cannot perform its purpose if the initial resource acquisition failed. This way the error is handled where it occurred. Even in less extreme cases (e.g. when an object is created at the beginning of a large function other than main) this may be the simpler solution.
In code, my suggestion looks like this:
struct T2;
struct myEx { myEx(const char *); };
void exit(int);
T1 *acquireResource1(); // e.g. read file
T2 *acquireResource2(); // e.g. connect to db
void log(const char *what);
class ObjT
{
public:
struct RsrcT
{
T1 *mT1;
T2 *mT2;
operator bool() { return mT1 && mT2; }
};
ObjT(const RsrcT& res) noexcept
{
// initialize from file data etc.
}
// more member functions using data from file and db
};
int main()
{
ObjT::RsrcT rsrc = { acquireResource1(), acquireResource2() };
if(!rsrc)
{
log("bummer");
exit(1);
}
///////////////////////////////////////////////////
// all resources are available. "Real" code starts here.
///////////////////////////////////////////////////
ObjT obj(rsrc);
// 1000 lines of code using obj
}

What's the proper way to have a Task that calls an arbitrary function with a known, specific return type?

I have a value which is expensive to calculate and can be asked for ahead of time--something like a lazily initiated value whose initialization is actually done at the moment of definition, but in a different thread. My immediate thought was to use parallelism.-Task seems purpose-built for this exact use-case. So, let's put it in a class:
class Foo
{
import std.parallelism : Task,task;
static int calculate(int a, int b)
{
return a+b;
}
private Task!(calculate,int,int)* ourTask;
private int _val;
int val()
{
return ourTask.workForce();
}
this(int a, int b)
{
ourTask = task!calculate(a,b);
}
}
That seems all well and good... except when I want the task to be based on a non-static method, in which case I want to make the task a delegate, in which case I start having to do stuff like this:
private typeof(task(&classFunc)) working;
And then, as it turns out, typeof(task(&classFunc)), when it's asked for outside of a function body, is actually Task!(run,ReturnType!classFunc function(Parameters!classFunc))*, which you may notice is not the type actually returned by runtime function calls of that. That would be Task!(run,ReturnType!classFunc delegate(Parameters!classFunc))*, which requires me to cast to typeof(working) when I actually call task(&classFunc). This is all extremely hackish feeling.
This was my attempt at a general template solution:
/**
Provides a transparent wrapper that allows for lazy
setting of variables. When lazySet!!func(args) is called
on the value, the function will be called in a new thread;
as soon as the value's access is attempted, it'll return the
result of the task, blocking if it's not done calculating.
Accessing the value is as simple as using it like the
type it's templated for--see the unit test.
*/
shared struct LazySet(T)
{
/// You can set the value directly, as normal--this throws away the current task.
void opAssign(T n)
{
import core.atomic : atomicStore;
working = false;
atomicStore(_val,n);
}
import std.traits : ReturnType;
/**
Called the same way as std.parallelism.task;
after this is called, the next attempt to access
the value will result in the value being set from
the result of the given function before it's returned.
If the task isn't done, it'll wait on the task to be done
once accessed, using workForce.
*/
void lazySet(alias func,Args...)(Args args)
if(is(ReturnType!func == T))
{
import std.parallelism : task,taskPool;
auto t = task!func(args);
taskPool.put(t);
curTask = (() => t.workForce);
working = true;
}
/// ditto
void lazySet(F,Args...)(F fpOrDelegate, ref Args args)
if(is(ReturnType!F == T))
{
import std.parallelism : task,taskPool;
auto t = task(fpOrDelegate,args);
taskPool.put(t);
curTask = (() => t.workForce);
working = true;
}
private:
T _val;
T delegate() curTask;
bool working = false;
T val()
{
import core.atomic : atomicStore,atomicLoad;
if(working)
{
atomicStore(_val,curTask());
working = false;
}
return atomicLoad(_val);
}
// alias this is inherently public
alias val this;
}
This lets me call lazySet using any function, function pointer or delegate that returns T, and then it'll calculate the value in parallel and return it, fully calculated, next time anything tries to access the underlying value, exactly as I wanted. Unit tests I wrote to describe its functionality pass, etc., it works perfectly.
But one thing's bothering me:
curTask = (() => t.workForce);
Moving the Task around by way of creating a lambda on-the-spot that happens to have the Task in its context still seems like I'm trying to "pull one over" on the language, even if it's less "hackish-feeling" than all the casting from earlier.
Am I missing some obvious language feature that would allow me to do this more "elegantly"?
Templates that take an alias function parameter (such as the Task family) are finicky regarding their actual type, as they can receive any type of function as parameter (including in-place delegates that get inferred themselves). As the actual function that gets called is part of the type itself, you would have to pass it to your custom struct to be able to save the Task directly.
As for the legitimacy of your solution, there is nothing wrong with storing lambdas to interact with complicated (or "hidden") types later.
An alternative is to store a pointer to &t.workForce directly.
Also, in your T val() two threads could enter if(working) at the same time, but I guess due to the atomic store it wouldn't really break anything - anyway, that could be fixed by core.atomic.cas.

I get an uninitialized object from a pointer

So i have some troubles getting pointers to work with SFML shapes. I'm not sure if it has something to do with SFML or if I'm doing anything wrong.
In Draw() x(a ControlWindow) does not contain valid values, it only shows "???" as shown here. However the m_controls(map) contains the correct values for the control object.
I'm quite new to C++ so any help would be greatly appreciated.
Exception
Exception thrown at 0x60B26EE5 (sfml-graphics-2.dll) in OokiiUI.exe: 0xC0000005: Access violation reading location 0x00000000.
Main
vector<WindowControl> windowControls;
void Draw ();
int main ()
{
RectangleShape rect(Vector2f(120,120));
WindowControl windowControl(nullptr,0);
Control testControl(&windowControl,1);
testControl.SetShape(&rect);
windowControl.AddControl(testControl);
windowControls.push_back(windowControl);
return 0;
}
WindowControl
class WindowControl : Control
{
public:
WindowControl ( WindowControl * windowControl, uint64_t uint64 )
: Control ( windowControl, uint64 )
{
}
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
m_controlPtrs.push_back(&control);
}
vector<Control*>* GetControls()
{
return &m_controlPtrs;
}
private:
map<uint64_t, Control> m_controls;
vector<Control*> m_controlPtrs;
};
Draw
for (auto x : windowControls)
{
vector<Control*> *controlPtrs = x.GetControls();
window->draw(x.GetControl(0)->GetShape());
}
There is a problem here:
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
m_controlPtrs.push_back(&control);
}
You add the address of the parameter control which is destroyed when the function ends. It looks like you want to add the address of the copy that you add to your map like this:
void AddControl(Control control)
{
m_controls.insert_or_assign(control.GetId(), control);
// don't use the parameter here, use the copy you put in the map
m_controlPtrs.push_back(&m_controls[control.GetId()]);
}
Although that is not ideal because if you send the same control twice, it will only appear once in the map (updated) but twice in the vector of pointers. You can use the returned pait from insert_or_update to fix that:
void AddControl(Control control)
{
auto [iter, was_inserted] = m_controls.insert_or_assign(control.GetId(), control);
// only add to vector if it was not in the map before
if(was_inserted)
m_controlPtrs.push_back(&iter->second);
}
A side note:
It is more idiomatic to return a reference in this situation rather than a pointer:
vector<Control*>& GetControls()
{
return m_controlPtrs;
}
This also breaks encapsulation so it may be worth thinking about how you can avoid accessing the internals of your objects so directly.
Your problem is that you are adding the pointer of a local variable into your m_controlPtrs:
void AddControl(Control control)
{
m_controlPtrs.push_back(&control);
}
Here you take a copy of Control, then add the address of that into your vector. The moment the function returns, your object goes out of scope and that memory is pointing to uninitialised garbage.
You probably want to update AddControl to take a Control&.
#ShadowRanger raises a good point in the comments: what I've mentioned may fix your issue, perhaps indefinitely, but your design still isn't terrific. Any time you have a Control which won't outlive m_controlPtrs you're going to encounter this same problem. Your code is small now, but this may eventually turn into a nightmare to fix. It's likely you should instead update m_controlPtrs to share (or take) ownership of the Control so this problem won't occur.
The easiest way out is to have m_controlPtrs declared as a std::vector<std::shared_ptr<Control>>, but it's something you should think about.

Implementation of config file

I am making an application in C++, and it requires a config file that will be read and interpreted on launch. It will contain things such as:
Module1=true
Now, my original plan was to store it all in variables and simply have
If(module1) {
DO_STUFF();
}
However this seems wasteful as it would be checking constantly for a value that would never change. Any ideas?
Optimize the code, only if you find a bottleneck with a profiler. Branch prediction should do its thing here, module1 never changes, so if you call it in a loop, even, there shouldn't be a noticeable performance loss.
If you want to experiment, you can branch once, and make a pointer point to the right function:
using func_ptr = void (*)();
func_ptr p = [](){};
if(module1)
p = DO_STUFF;
while(...)
p();
But this is just something to profile, look at the assembly...
There are also slower, but comfortable ways you could be storing the configuration, e.g. in an array with enumerated indexes, or a map. If I were to get some value in a loop, I'd do:
auto module1 = modules[MODULE1]; // array and enumeration
//auto module1 = modules.at("module1"); // map and string
while(...)
{
if(module1)
DO_STUFF;
...
}
So I'd end up with what you already have.
performance wise a boolean check is no problem, except you start doing it millions or billions of times. Maybe you can start merging code which belongs to module1, but other than that you'd have to check for it like you currently do
This really isn't an issue. If your program requires that Module1 should be true then let it check the value and continue on. It wont affect your performance unless it is being checked too many times.
One thing you could do is make an inline function if it being checked too many times. However, you will have to make sure the function shouldnt be too big otherwise it will be a bigger bottleneck
Sorry guys, didn't spot this when I looked it up:
MDSN
So I check the boolean once on launch and then I don't need to anymore as only the correct functions are launched.
Depending on how your program is set up and how the variables change the behaviour of the code you might be able to use function pointers:
if(Module1 == true)
{
std::function<void(int)> DoStuff = Module1Stuff;
}
And then later:
while(true)
{
DoStuff(ImportantVariable);
}
See http://en.cppreference.com/w/cpp/utility/functional/function for further reference.
Not that I think it'll help all that much but it's an alternative to try out at least.
This can be solved if you know the all use cases of the values you check. For example, if you've read your config file and module1 is true - you do one thing, if it is false - another. Let's start with example:
class ConfigFileWorker {
public:
virtual void run() = 0;
};
class WithModule1Worker {
public:
void run() final override {
// do stuff as if your `Module1` is true
}
};
class WithoutModule1Worker {
public:
void run() final override {
// do stuff as if your `Module1` is false
}
};
int main() {
std::unique_ptr<ConfigFileWorker> worker;
const bool Module1 = read_config_file(file, "Module1");
if (Module1) { // you check this only once during launch and just use `worker` all the time after
worker.reset(new WithModule1Worker);
} else {
worker.reset(new WithoutModule1Worker);
}
// here and after just use the pointer with `run()` - then you will not need to check the variable all the time, you'll just perform action.
}
So you have predefined behaviour for 2 cases (true and false) and just create an object of one of them during parsing the config file on launch. This is java-like code, but of course you may use function pointers, std::function and other abstractions instead of a base class, however, base class-option has more flexibility in my opinion.