I'm playing around with std::atomic
but I think I didn't fully understand the concept. I'm wondering why there are no atomic Containers. So I played a little bit around. First I tried the following:
std::atomic<std::list<int> > atomicList;
But as already some other people pointed out that this doesn't work because the constructor is noexcept
. So I created some kind of hack:
template<class T>
class MyList
{
public:
//Make sure that no exception is thrown
MyList() noexcept
try: l()
{}catch(...) {}
void push_back(const T &t) { l.push_back(t); }
void pop_front() { l.pop_front(); }
size_t size() const { return l.size(); }
private:
list<T> l;
};
atomic<MyList<int> > atomicList;
Now I worked with it but I discovered that it doesn't work properly and I get Segmentation fault errors.
Can somebody please explain why it is not possible to create an atomic list this way?
EDIT: If someone wants to see how my test program really looks for better understanding:
#include <list>
#include <thread>
#include <sys/time.h>
#include <iostream>
#include <atomic>
using namespace std;
template<class T>
class MyList
{
public:
MyList() noexcept
try: l()
{}catch(...) {}
void push_back(const T &t) { l.push_back(t); }
void pop_front() { l.pop_front(); }
size_t size() const { return l.size(); }
private:
list<T> l;
};
atomic<MyList<int> > l;
void work()
{
for(unsigned int i = 0; i < 100000; ++i)
{
//Called operator()
((MyList<int>&)l).push_back(i);
((MyList<int>&)l).push_back(((MyList<int>&)l).size());
((MyList<int>&)l).pop_front();
}
}
int main(int argc, char *args[])
{
struct timeval time1;
struct timeval time2;
gettimeofday(&time1, 0);
thread t1(work);
thread t2(work);
thread t3(work);
thread t4(work);
t1.join();
t2.join();
t3.join();
t4.join();
gettimeofday(&time2, 0);
cout<<((time2.tv_sec-time1.tv_sec)+double(time2.tv_usec-time1.tv_usec)/1000000)<<endl;
}
The first and most important problem: this can't possibly work. You need synchronization around the execution of the member functions, not around retrieving the list.
std::atomic
doesn't even begin to resemble what you need.Regarding your attempted implementation, casting an
atomic<T>
toT&
can't do anything reasonable.And even if it were meaningful, such a cast would completely forget the atomicness of your object, and so anything you do with the references won't be atomic operations.