Weird behaviour changing captured atomic bool - c++

I am doing something like this with TBB:
#include <tbb/tbb.h>
#include <memory>
#include <atomic>
class base_creator
{
public:
using node = tbb::flow::input_node<bool>;
virtual ~base_creator() = default;
base_creator()
{
m_kill = std::make_shared<std::atomic_bool>(false);
};
static tbb::flow::graph& g()
{
static tbb::flow::graph me_g;
return me_g;
};
virtual std::shared_ptr<node> get_node() const = 0;
template<typename Op>
static tbb::flow::input_node<bool> build_node(const Op& op)
{
return tbb::flow::input_node<bool>(base_creator::g(), op);
};
protected:
mutable std::shared_ptr<std::atomic_bool> m_kill;
};
class creater : public base_creator
{
public:
creater() = default;
public:
virtual std::shared_ptr<node> get_node() const override
{
const std::shared_ptr<std::atomic_bool> flag = this->m_kill;
auto op = [flag](flow_control& control) -> bool
{
if (flag->load(std::memory_order_relaxed))
control.stop();
return true;
};
node nd = base_creator::build_node(std::cref(op));
return std::make_shared<node>(nd);
};
};
int main(int argc, char* argv[])
{
creater c;
std::shared_ptr<base_creator::node> s = c.get_node();
using my_func_node = std::shared_ptr<tbb::flow::function_node<bool, bool>>;
my_func_node f = std::make_shared<tbb::flow::function_node<bool, bool>>(base_creator::g(), 1,[](const bool b) { std::cout << b; return b; });
tbb::flow::make_edge(*s, *f);
};
The flag should be always false in this code. Once I call tbb::flow::make_edge it becomes true when debugging the body of the node s in THAT IS SO WEIRD? I have no clue, could you please help, I am starting to hit in the TBB code now and it's too complex :)

Pay attention to the following code. It creates std::reference_wrapper over local object op that is copied into input_node with build_node. Therefore, when get_node returns the std::reference_wrapper (that is inside the node that is inside shared_ptr), it references the destroyed object. Then, make_edge reuses the stack and replaces flag pointer with some other pointer that contains 72.
auto op = [flag](flow_control& control) -> bool
{
if (flag->load(std::memory_order_relaxed))
control.stop();
return true;
};
node nd = base_creator::build_node(std::cref(op));

Related

This C++ class for storing set of shared_ptr: is it thread safe?

Assume C++17 (some of this is deprecated in C++20)
I have written a class EventDB that stores a fixed set of shared_ptr.
class EventDB
{
public:
EventDB() = delete;
EventDB(const std::vector<std::shared_ptr<const EventInfo>>& init_events):
PointEvents(init_events.begin(),init_events.end())
{}
std::shared_ptr<const EventInfo> Swap(std::shared_ptr<const EventInfo> event)
{
auto old_it = PointEvents.find(event);
if(old_it == PointEvents.end())
return nullptr;
//cast away the constness of the iterator element
//is this OK, because we know we're not changing its hash/equality?
auto old_evt_addr = &const_cast<std::shared_ptr<const EventInfo>&>(*old_it);
return std::atomic_exchange(old_evt_addr,event);
}
private:
std::unordered_set<std::shared_ptr<const EventInfo>,EventPointHash,EventPointEq> PointEvents;
};
It provides a way to swap out the elements of the set using std::atomic_exchange.
'swapping out' an element of a set may seem pointless, but I provide custom hasher and equality for the set, so the swapped elements actually hold different data even though they're equivalent from the perspective of the set. The correctness of all this is the subject of a secondary question, because I could just replace it with a map if I needed to.
My main question is about thread safety - is EventDB thread safe, and if not, why not?
The secondary question alluded to above is how bad it is to cast away the constness of the set iterator so I can (atomically) modify the element. Am I breaking the rules of the language and relying on implementation specific behaviour? Or is this technically allowed?
For bonus kudos, what would I replace std::atomic_exchange with in C++20. I know there are proper atomic smart pointer, but could I convert between normal shared_ptr in this example?
Here's some self-contained code that compiles and works with g++ 9.3.0 GLIBCXX_3.4.28
#include <vector>
#include <string>
#include <iostream>
#include <thread>
#include <memory>
#include <limits>
#include <unordered_set>
enum class EventType : uint8_t
{
RED = 0,
BLUE = 1
};
class EventInfo
{
public:
EventInfo() = delete;
EventInfo(const EventType t, const size_t i, const std::string& p):
Type(t),Index(i),Payload(p)
{}
size_t GetIndex() const
{
return Index;
}
EventType GetEventType() const
{
return Type;
}
const std::string& GetPayload() const
{
return Payload;
}
private:
EventType Type;
size_t Index;
std::string Payload;
};
struct EventPointHash
{
size_t operator()(const std::shared_ptr<const EventInfo>& evt) const
{
if(!evt)
return std::numeric_limits<size_t>::max();
return (evt->GetIndex() << (sizeof(EventType)<<3)) + static_cast<size_t>(evt->GetEventType());
}
};
struct EventPointEq
{
bool operator()(const std::shared_ptr<const EventInfo>& lhs,
const std::shared_ptr<const EventInfo>& rhs) const
{
if(!lhs && !rhs) return true;
if(!lhs || !rhs) return false;
return (lhs->GetIndex() == rhs->GetIndex() && lhs->GetEventType() == rhs->GetEventType());
}
};
class EventDB
{
public:
EventDB() = delete;
EventDB(const std::vector<std::shared_ptr<const EventInfo>>& init_events):
PointEvents(init_events.begin(),init_events.end())
{}
std::shared_ptr<const EventInfo> Swap(std::shared_ptr<const EventInfo> event)
{
auto old_it = PointEvents.find(event);
if(old_it == PointEvents.end())
return nullptr;
//cast away the constness of the iterator element
//is this OK, because we know we're not changing its hash/equality?
auto old_evt_addr = &const_cast<std::shared_ptr<const EventInfo>&>(*old_it);
return std::atomic_exchange(old_evt_addr,event);
}
private:
std::unordered_set<std::shared_ptr<const EventInfo>,EventPointHash,EventPointEq> PointEvents;
};
int main()
{
//create a database to hold 100 events
std::vector<std::shared_ptr<const EventInfo>> init_events;
for(int i=0;i<100;i++)
{
init_events.emplace_back(std::make_shared<const EventInfo>(EventType::RED,i,"-1"));
}
EventDB DB(init_events);
//Access the element concurrently
std::vector<std::thread> threads;
for(int i = 0;i<5;i++)
{
threads.emplace_back([&]()
{
for(int j = 0;j<1000000;j++)
{
//replace a random element
auto event = std::make_shared<const EventInfo>(EventType::RED,rand()%100,std::to_string(j));
auto old_evt = DB.Swap(event);
//access the data - randomly print
if(old_evt && std::stoi(old_evt->GetPayload())%2000 == 0 && old_evt->GetIndex() == 66)
std::cout<<"Replaced "<<old_evt->GetPayload()<<" with "<<event->GetPayload()<<std::endl;
}
});
}
init_events.clear();
for(auto& t : threads)
t.join();
return 0;
}
Typical output:
Replaced 20000 with 20033
Replaced 134000 with 134002
Replaced 144000 with 143694
Replaced 144000 with 144435
Replaced 172000 with 174980
Replaced 252000 with 255578
Replaced 258000 with 252434
Replaced 368000 with 367261
Replaced 498000 with 497470
Replaced 584000 with 583205
Replaced 628000 with 619809
Replaced 722000 with 722603
Replaced 730000 with 722302
Replaced 780000 with 768508
Replaced 784000 with 784036
Replaced 816000 with 821799
Replaced 842000 with 844719
Replaced 970000 with 950851
Edit:
Igor's answer pointed me to the data race. I was then able to easily modify the code to prove it in practice.
Adding a destructor that messed up the hash if a destroyed element was used, and then printing a message when find failed:
~EventInfo()
{
//these aren't used in the example
// - so they will mess up find when the race is lost
Index = 200;
Type = EventType::BLUE;
}
auto old_evt = DB.Swap(event);
if(!old_evt)
std::cout<<"BOOM"<<std::endl;
And sure enough:
BOOM
BOOM
BOOM
BOOM
Fixed code (unless someone finds something else!)##
This is my attemp to implement the fix suggested in Igor's answer
#include <vector>
#include <string>
#include <iostream>
#include <thread>
#include <memory>
#include <limits>
#include <unordered_map>
enum class EventType : uint8_t
{
RED = 0,
BLUE = 1
};
class EventInfo
{
public:
EventInfo() = delete;
EventInfo(const EventType t, const size_t i, const std::string& p):
Type(t),Index(i),Payload(p)
{}
size_t GetIndex() const
{
return Index;
}
EventType GetEventType() const
{
return Type;
}
const std::string& GetPayload() const
{
return Payload;
}
private:
EventType Type;
size_t Index;
std::string Payload;
};
struct EventPointHash
{
size_t operator()(const std::pair<EventType,size_t>& point) const
{
return (point.second << (sizeof(EventType)<<3)) + static_cast<size_t>(point.first);
}
};
class EventDB
{
public:
EventDB() = delete;
EventDB(const std::vector<std::shared_ptr<const EventInfo>>& init_events)
{
for(const auto& event : init_events)
PointEvents[{event->GetEventType(),event->GetIndex()}] = event;
}
std::shared_ptr<const EventInfo> Swap(const std::shared_ptr<const EventInfo> event)
{
auto old_it = PointEvents.find({event->GetEventType(),event->GetIndex()});
if(old_it == PointEvents.end())
return nullptr;
auto old_evt_addr = &(old_it->second);
return std::atomic_exchange(old_evt_addr,event);
}
private:
std::unordered_map<std::pair<EventType,size_t>,std::shared_ptr<const EventInfo>,EventPointHash> PointEvents;
};
int main()
{
//create a database to hold 100 events
std::vector<std::shared_ptr<const EventInfo>> init_events;
for(int i=0;i<100;i++)
{
init_events.emplace_back(std::make_shared<const EventInfo>(EventType::RED,i,"-1"));
}
EventDB DB(init_events);
init_events.clear();
//Access the element concurrently
std::vector<std::thread> threads;
for(int i = 0;i<5;i++)
{
threads.emplace_back([&]()
{
for(int j = 0;j<1000000;j++)
{
//replace a random element
auto event = std::make_shared<const EventInfo>(EventType::RED,rand()%100,std::to_string(j));
auto old_evt = DB.Swap(event);
if(!old_evt)
{
std::cout<<"BOOM"<<std::endl;
continue;
}
//access the data - randomly print
if(std::stoi(old_evt->GetPayload())%2000 == 0 && old_evt->GetIndex() == 66)
std::cout<<"Replaced "<<old_evt->GetPayload()<<" with "<<event->GetPayload()<<std::endl;
}
});
}
for(auto& t : threads)
t.join();
return 0;
}
There's a data race. While writing the set's elements is atomic via std::atomic_exchange, reading them inside find is not. find may see a torn read if another thread swaps an element right from under it.
There's a subtler scenario: one thread has called PointEvents.find(event), and find is currently reading the contents of some EventInfo instance in the set (let's call it X), to compute its hash or compare it to event. At the same time, another thread performs Swap on that same element and returns the shared pointer holding X to the caller. The caller perhaps looks at X briefly then allows the shared pointer to be destroyed, and X together with it. find then races with X's destructor.
Consider separating fixed parts of EventInfo that contribute to the hash and equality, from the payload part that can vary. Store them in std::unordered_map, with fixed part as the key and the payload as the value. Then you can swap the payload without affecting find.

Initialization of anonymous class member variable with std::function

I wonder if there is a workaround is such situation:
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = initB(10);
std::function<decltype(B)(int)> initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
}
//...
A a; //crash
//...
I suppose it is caused by order of initialization. Variable B is initilized by calling an uninitilized std::function instance, hence the crash. By my logic, the workaround would be to initialize std::function first, then initialize member B. But then, such code is not valid:
class A
{
//error: 'B' was not declared in this scope
std::function<decltype(B)(int)> initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = initB(10);
}
I tried to make to make the std::function static, and such code works, but requires non-constexpr/const member, because std::function has non-trivial destructor - which is bad, because that requires source file, which requires creating such file, which requires some efford and destruction of my beautiful header-only class hierarchy! (I mean, I could be lazy and define this variable in the header, but then the multiple definition problem occurs). I know it might be a bad design (i'm just testing things out), but do you have any ideas how the problem can be solved without involving source files?
Although your example is contrived, there are times when I've needed (or its more convenient) to initialize complex objects in a similar way.
But, why use std::function<>? Why not just use a function?
class A
{
class
{
public:
void setValue(int val) { i = val; }
private:
int i;
} B = initB(10);
static decltype(B) initB(int value)
{
decltype(B) temp;
temp.setValue(value);
return temp;
}
};
Although, I wouldn't normally use decltype(B); I would just give the class a name.
I feel like I am somehow subverting your intent, but if you initialize the variables in the constructor, you can make things work.
#include <functional>
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B;
std::function<decltype(B)(int)> initB;
public:
A() {
initB = [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;};
B = initB(10);
}
};
int main() {
A a;
}
A::initB is a value. It's not initialized at the point where you call it, because initialization is done (loosely speaking) in the order you specify member fields. You can verify this by executing the below, which works:
#include <iostream>
#include <functional>
using namespace std;
template<typename T, typename U>
T set(T& tgt, const U& src)
{
new(&tgt) T(src);
return tgt;
}
class A
{
class
{
public:
void setValue(int val) {i=val;}
private:
int i;
} B = set(initB, [this](int value)
{decltype(B) temp;
temp.setValue(value);
return temp;})(10);
std::function<decltype(B)(int)> initB;
};
int main() {
A a;
}

Initializing many private variables in one line

I'm working on legacy code which looks like the following:
class Foo {
public:
Foo();
private:
bool a1, a2, a3 /*, ...*/, a50;
};
Foo::Foo() {
a1 = a2 = a3 /* = ... */ = a50 = false;
}
This is messy. Is there a way to default all private variables of the same time to a single value that's different from the above? I don't want to use an initializer list because there are so many variables.
I know the default constructor of bool assigns false - can this be leveraged?
There are many possible ways to do it, but all of them are very similar. Anyway you will assign each your variable using different forms.
The main method which I think the best is right assign all variables at your constructor line by line. May be its not compact, but it the most meaningful and you allways can easy look your variables default value:
Foo::Foo() {
a1 = false;
a2 = false;
/*...*/
a50 = false;
}
Another method is which you described, with assign operators:
Foo::Foo() {
a1 = a2 = a3 /* = ... */ = a50 = false;
}
And another one allows initialize variables right after constructor declaration:
Foo::Foo() :
a1(false),
a2(false),
/*...*/
a50(true)
{ }
If I forget any method write it to comments, please.
class Foo
{
private:
bool a1{}, a2{}, /*...,*/ a50{};
};
try with this
Foo::Foo (bool aa) : a1 (aa) , a2 (aa), a3 (aa),/*......*/a50(aa){}
You can have another class (in a separate header) which looks like following.
class myBool {
public:
myBool(int x = 1) { _m = x; }
operator bool() const { return 0 < _m; }
private:
int _m;
};
and in your file you can add following
#include "myBool.h"
#define bool myBool
This will initialize all of bool to default value you set in myBool. You may need to add some more methods to myBool class to use it as a full fledge data type. Above is the bare minimum to explain the answer.
Here is an alternative solution to the ones I've seen posted so far, in case it's useful to you.
Put the data you want to mass-initialize to a default false/0 value in its own struct:
struct MyData
{
bool a, b, c, d;
std::string e, f;
};
Now inherit (privately or otherwise) from this struct, and explicitly initialize it in the constructor's initialization list:
class MyClass : private MyData
{
public:
MyClass()
: MyData()
{
}
};
This sets all the bools to false, the strings are empty, any ints become 0, pointers become null, etc, etc
If you forget to put the struct explicitly in the initialization list, some of its members may be uninitialized.
Confirming that it always requires more work to be lazy in c++...
#include <iostream>
#include <utility>
template<class Tuple, std::size_t...Is>
void zero_out_impl(Tuple& t, std::index_sequence<Is...>)
{
using expand = bool[];
(void) expand { false, (std::get<Is>(t) = false)... };
}
template<class...Args>
void zero_out(std::tuple<Args...> t)
{
zero_out_impl(t, std::index_sequence_for<Args...>());
}
struct lots_of_bools {
lots_of_bools()
{
zero_out(std::tie(a,b,c,d,e,f,g,h,i,j));
}
private:
bool a,b,c,d,e,f,g,h,i,j;
};
auto main() -> int
{
lots_of_bools x;
return 0;
}
Here's another way - wrap the bool in a wrapper that default-constructs it.
#include <iostream>
struct auto_false
{
auto_false(bool initial = false) : value(initial) {};
operator bool() const { return value; }
operator bool& () { return value; }
private:
bool value;
};
struct lots_of_bools {
lots_of_bools()
{
}
bool value_of_f() const {
return f;
}
void set_f(bool val) {
f = val;
}
private:
auto_false a,b,c,d,e,f,g,h,i,j;
};
using namespace std;
auto main() -> int
{
lots_of_bools x;
cout << x.value_of_f() << endl;
x.set_f(true);
cout << x.value_of_f() << endl;
return 0;
}
output:
0
1

Function pointer to a template class

I need some help on a strange mix between function pointers and templates...
My target :
You have a class : template<typename B> class A, and A instanciate a B member. Now I want to acces B getter/setter.
I tried this :
class B_example
{
public:
B_example(int v):m_var(v){}
int getVar() { return m_var; }
void setVar(int v) { m_var = v; }
private:
int m_var;
};
template<typename B> class A
{
public:
A():m_b(B(5))
{
get = &m_b.getVar;
set = &m_b.setVar;
}
int (B::*get)();
void (B::*set)(int);
private:
B m_b;
};
int main(int argc, char** argv)
{
A<B_example> A_instance;
B_example B_instance(5);
int a = (A_instance.get*)();
std::cout << a << std::endl;
}
Thank's for any help.
Alexandre
First, fix the syntax errors:
get = &B::getVar;
set = &B::setVar;
Then, the member-function pointer needs to be called on an object. Without knowing the purpose of these strange pointers, I can't guess what you want to do here. Maybe you want to call on B_instance:
int a = (B_instance.*A_instance.get)();
Or maybe you want to call it on the m_b object within A_instance; but you can't do that because it's private. If that's the case, you probably just want regular member functions, rather than weird function pointers
int get() {return m_b.getVar();}
void set(int v) {m_b.setVar(v);}
These:
get = &m_b.getVar;
set = &m_b.setVar;
Should be:
get = &B::getVar;
set = &B::setVar;
And (A_instance.get*)() should be (B_instance.*A_instance.get)().

std::bind vs std::shared_ptr

Can't understand how to use shared_ptr binded to class function.
An error occurrs at line USE because compiler can't convert shared_ptr to A.
#include <functional>
class A {
public:
const bool check(void) const { return true; };
};
int _tmain(int argc, _TCHAR* argv[]) {
const std::function<const bool(const A)> f_check = &A::check;
auto a = std::make_shared<const A>();
auto f_check_a = std::bind(f_check, a); // line BIND
auto res = f_check_a(); // line USE - ERROR!!!
return 0;
}
I can replace line BIND to access real value of smart pointer:
int _tmain(int argc, _TCHAR* argv[]) {
auto f_check = &A::check;
auto a = std::make_shared<const A>();
auto f_check_a = std::bind(f_check, *a.get()); // line BIND
auto res = f_check_a(); // line USE - NO ERRORS
return 0;
}
Now code is compiled and may be it will work.
But I'd like to know - is it acceptable way to use raw value from smart pointer? May I somehow use shared_ptr instead raw value?
UPD2:
Looks like my colleague have found a nice workaround:
class A {
public:
const bool check(void) const { return true; };
};
using p_func = const bool(A::*)() const;
int _tmain(int argc, _TCHAR* argv[]) {
auto a = std::make_shared<const A>();
p_func b = &A::check;
auto f_check_a = std::bind(b, a);
auto res = f_check_a();
}
Now I can send b as argument and bind to shared_ptr.
UPD:
I can't use lambda in my real task.
Here is some more code from real project:
#include <functional>
#include <algorithm>
class Block {
public:
const bool check1(void) const { return false; };
const bool check2(void) const { return false; };
const bool check3(void) const { return false; };
};
using block_t = std::shared_ptr<const Block>;
class Worker {
private:
std::vector<const block_t> _container;
public:
void processor(const std::function<const bool(const Block)> f_check) {
block_t my_block = nullptr;
auto lambda = [my_block, f_check](const block_t block) mutable {
auto function_check = std::bind(f_check, *block.get());
if (function_check()) {
my_block = block;
return true;
}
return false;
};
std::find_if(_container.begin(), _container.end(), lambda);
}
};
void test(block_t block) {
Worker worker;
worker.processor(&Block::check1);
worker.processor(&Block::check2);
worker.processor(&Block::check3);
}
UPD3:
Fixed code without smart pointer dereferencing:
#include <functional>
#include <algorithm>
class Block {
public:
const bool check1(void) const { return false; };
const bool check2(void) const { return false; };
const bool check3(void) const { return false; };
};
using block_t = std::shared_ptr<const Block>;
using p_func = const bool(Block::*)() const;
class Worker {
private:
std::vector<const block_t> _container;
public:
void processor(p_func f_check) {
block_t my_block = nullptr;
auto lambda = [my_block, f_check](const block_t block) mutable {
auto function_check = std::bind(f_check, block);
if (function_check()) {
my_block = block;
return true;
}
return false;
};
std::find_if(_container.begin(), _container.end(), lambda);
}
};
void test(block_t block) {
Worker worker;
worker.processor(&Block::check1);
worker.processor(&Block::check2);
worker.processor(&Block::check3);
}
Your problem is that you are first creating a std::function, expecting an A instance, from a member function and than trying to bind it to a shared_ptr. You can skip that part:
auto a = std::make_shared<const A>();
auto f_check_a = std::bind(&A::check, a);
auto res = f_check_a();
std::bind knows how to directly bind a member function to a shared_ptr.
Must you use std::bind? You could use a lambda instead.
auto f_check_a = [=]{ return a->check(); };
function expects to get an instance of A, not a shared_ptr<A>, so the answer to your question is basically yes, I believe.
However, I would make 2 changes to your code as follows (see my comments):
const std::function<const bool(const A&)> f_check = &A::check; // <-- Added & after A here
auto a = std::make_shared<const A>();
auto f_check_a = std::bind(f_check, *a); // <-- no need to call get() on a
auto res = f_check_a(); // line USE - ERROR!!!
But I'd like to know - is it acceptable way to use raw value from smart pointer?
Yes, but you can just write *a instead of *a.get()
However, the call wrapper returned from bind has a reference to theA object, so it is your responsibility to ensure the reference remains valid. If you bound the shared_ptr then that would increase the reference count and keep the object alive.
May I somehow use shared_ptr instead raw value?
If you use std::function<const bool(const A)> then you cannot pass a shared_ptr<const A>.
When you use std::function<const bool(const A)> you create a callable type that has exactly the call signature const bool(const A) and so you have to pass it an argument that is convertible to const A, and shared_ptr<const A> is not convertible to const A.
A workaround would be to use a lambda to combine the std::function and shared_ptr:
auto function_check = [] { return f_check(*block); };
if (function_check()) {
However, you are trying to solve a problem that shouldn't exist, just do this instead:
if (f_check(*block)) {
my_block = block;
return true;
}
return false;
Then you don't need to bind anything.