I need to work with array from several threads, so I use CRITICAL SECTION to give it an exclusive access to the data.
Here is my template:
#include "stdafx.h"
#ifndef SHAREDVECTOR_H
#define SHAREDVECTOR_H
#include <vector>
#include <windows.h>
template<class T>
class SharedVector {
std::vector<T> vect;
CRITICAL_SECTION cs;
SharedVector(const SharedVector<T>& rhs) {}
public:
SharedVector();
explicit SharedVector(const CRITICAL_SECTION& CS);
void PushBack(const T& value);
void PopBack();
unsigned int size() const;
T& operator[](int index);
virtual ~SharedVector();
};
template<class T>
SharedVector<T>::SharedVector() {
InitializeCriticalSection(&cs);
}
template<class T>
SharedVector<T>::SharedVector(const CRITICAL_SECTION& r): cs(r) {
InitializeCriticalSection(&cs);
}
template<class T>
void SharedVector<T>::PushBack(const T& value) {
EnterCriticalSection(&cs);
vect.push_back(value);
LeaveCriticalSection(&cs);
}
template<class T>
void SharedVector<T>::PopBack() {
EnterCriticalSection(&cs);
vect.pop_back();
LeaveCriticalSection(&cs);
}
template<class T>
unsigned int SharedVector<T>::size() const {
EnterCriticalSection(&cs);
unsigned int result = vect.size();
LeaveCriticalSection(&cs);
return result;
}
template<class T>
T& SharedVector<T>::operator[](int index) {
EnterCriticalSection(&cs);
T result = vect[index];
LeaveCriticalSection(&cs);
return result;
}
template<class T>
SharedVector<T>::~SharedVector() {
DeleteCriticalSection(&cs);
}
While compiling I have such a problem for calling EnterCriticalSection(&cs) and LeaveCriticalSection(&cs):
'EnterCriticalSection' : cannot convert parameter 1 from
'const CRITICAL_SECTION *' to 'LPCRITICAL_SECTION'
I do not know what is wrong. May be you can see. Just because I always used it this way and it was alright. windows.h is included
Just declare cs as:
mutable CRITICAL_SECTION cs;
or else remove the const clause on size()
Entering a critical section modifies the CRITICAL_SECTION, and leaving modifies it again. Since entering and leaving a critical section doesn't make the size() method call logically non-const, I'd say leave it declared const, and make cs mutable. This is the type of situation mutable was introduced for.
Also - take a look at Martin York's and Joe Mucchiello's suggestions - use RAII whenever possible to deal with any kind of resources that need to be cleaned up. This works just as well for critical sections as it does for pointers and file handles.
Also the code above is not Exception safe.
There is no guarantee that push_back() pop_back() will not throw. If they do they will leave your critical section permanently locked. You should create a locker class that calls EnterCriticalSection() on construction and LeaveCriticalSection() on destruction.
Also this makes your methods a lot easier to read. (see below)
class CriticalSectionLock
{
public:
CriticalSectionLock(CRITICAL_SECTION& cs)
: criticalSection(cs)
{
EnterCriticalSection(&criticalSection);
}
~CriticalSectionLock()
{
LeaveCriticalSection(&criticalSection);
}
private:
CRITICAL_SECTION& criticalSection;
};
// Usage
template
unsigned int SharedVector::size() const
{
CriticalSectionLock lock(cs);
return vect.size();
}
Another thing you should worry about. Is making sure that when you destroy the object you have ownership and that nobody else tries to take ownership during destruction. Hopefully your DestoryCriticalSection() takes care of this.
I prefer using a separate Acquisition object over your code. Your code if fragile when an exception occurs between the Enter and Leave calls:
class CS_Acquire {
CRITICAL_SECTION &cs;
public:
CS_Acquire(CRITICAL_SECTION& _cs) : cs(_cs) { EnterCriticalSection(cs); }
~CS_Acquire() { LeaveCriticalSection(cs); }
};
Then in your class methods you would code it as:
template <typename T>
void SharedVector::PushBack(const T& value) {
CS_Acquire acquire(&cs);
vect.push_back(value);
}
EnterCriticalSection doesn't take a const argument. That's a compilation error, BTW, not a linking error...
Also, are you sure you want to pass in a critical section into your ctor, and then have the ctor perform the InitializeCriticalSection call? If you want to share your critical section, I suppose you'd initialize it first, and then hand it out.
I see you have declared an empty copy constructor:
SharedVector(const SharedVector& rhs) {}
As I'm sure you are aware, this function does nothing, and it also leaves cs uninitialised. Because your class contains an instance of a CRITICAL_SECTION, you must be sure to disallow copy constructor and assignment operator calls unless you are going to implement them completely. You can do this by placing the following declarations in the private section of your class:
SharedVector(const SharedVector &);
SharedVector &operator=(const SharedVector &);
This prevents the compiler from auto-generating incorrect versions of these methods, and also prevents you from calling them in other code you write (because these are only declarations, but not definitions with {} code blocks).
Also, as Arnout mentioned, the constructor that takes a CRITICAL_SECTION& argument seems wrong. What your implementation does is copy the passed-in critical section to cs (which is not a valid thing to do with a CRITICAL_SECTION), then calls InitializeCriticalSection(&cs) which overwrites the copy you just did and creates a new critical section. To the caller who passed in a critical section, this seems to do the wrong thing by effectively ignoring whatever was passed in.
so, it`s something wrong with access rights.
I made size() method non-const and now it is ok.
Related
Suppose we have code like this:
template<class CALLBACK>
struct INIFile{
INIFile(CALLBACK &processor) :
processor(processor ){}
bool process(){
// lots of code here,
// call processor
processor(123);
return true;
}
CALLBACK &processor;
};
struct MyProcessor{
void operator()(int val){
// do something
}
};
struct MyConstProcessor{
void operator()(int val) const{ // !!!!!
// do something
}
};
int main(){
MyProcessor p;
INIFile<MyProcessor> ini(p);
ini.process();
// const case:
MyConstProcessor cp;
INIFile<MyConstProcessor> cini(cp);
cini.process();
}
In both cases INIFile<>::process() will be a non const member function.
Is there an easy way to make process() a const member function if CALLBACK::operator() is const, without duplicate all logic in INIFile<>::process()?
Your problem is solved by doing the following:
template<class CALLBACK>
struct INIFile{
INIFile(CALLBACK &processor) :
processor(processor){}
template <class T>
bool process_impl(T& processor) const {
// deliberately shadow processor
// reduce likelihood of using member processor, but can use other member variables
// lots of code
processor(123);
return true;
}
bool process() const {
return process_impl(const_cast<const CALLBACK&>(processor));
}
bool process() {
return process_impl(processor);
}
CALLBACK& processor;
};
This of course technically overloads process, but it has the exact same effect that you want. If the processor's call operator is not marked const, and you try to call process via a const reference or const copy of the object, you get a compilation error (unlike with your solution). That's because the const overload of process gets called, it adds the const to the processor which gets passed along, and then of course the call operator on the processor fails.
However, if the callback does provide a const call operator, then either process call will do exactly the same thing. This effectively means that you can call process on a const copy of INIFile, which is equivalent to process being const.
If the callback also overloads the call operator, then this implementation will forward along to whichever is correct, but you didn't specify that as a condition. The only thing to watch out for, is that process_impl should never access the member variable processor, because that member variable will always be mutable, i.e. the call will work even when it shouldn't (like in your solution). I shadow intentionally to try to prevent this. This isn't that beautiful but as an implementation detail it's not so bad, and it does remove the duplication.
Another way I found, but I do not like it very much is to use pointer instead of reference.
Here is the code.
Note in this particular case we do not need to check for nullptr at all.
template<class CALLBACK>
struct INIFile{
INIFile(CALLBACK &processor) :
processor(& processor ){}
bool process() const{
// lots of code here,
// call processor
processor->operator()(123);
return true;
}
CALLBACK *processor;
};
Recently I have read a part of "Concurrency in action" book concerning parallel quicksort implementation. I tried to check the code mentioned in the book and received an error on this part:
struct listPart
{
list<T> data;
promise<list<T>> promise;
};
listPart newLowerPart;
...
parts.push(move(newLowerPart));
The compiler gives the error
std::promise::promise(const std::promise> &) : attempting
to reference a deleted function.
The error is occured in generated copy constructor of listPart.
I guess trying to move newLowerPart it tries to use deleted copy constructor of promise. I thought creating custom copy constructor would help, but even an attempt to move promise inside it gave me the same error. Could you help me to solve this problem?
Thank you in advance
The problem is likely with your parts container implementation - it tries to copy the push parameter instead of moving it.
Here is an example:
#include <list>
#include <future>
struct listPart
{
std::list<int> data;
std::promise<std::list<int>> p;
};
template<typename T>
class dummy_container{
T t_;
public:
void push_back(const T& t){
t_ = t;
}
void move_back(const T& t){
t_ = t;
}
void move_back(T&& t){
t_ = std::move(t);
}
};
int main() {
dummy_container<listPart> dc;
listPart lp;
//dc.push_back(std::move(lp)); // won't compile, function only handles const references
dc.move_back(std::move(lp)); // will compile, because it moves if possible
}
Remember, that correct handling rvalues requires special treatment. So your container should provide at least two versions of push:
void push(const T& t); //'t' is coopied
and
void push(T&& t); //'t' is moved
Also, you should define move constructor for listPart and forbid copying:
Solution:
struct listPart
{
list<T> data;
promise<list<T>> promise;
listPart(const listPart&) = delete;
listPart(listPart&& source)
: data(std::move(source.data))
, promise(std::move(source.promise))
{ }
};
I thought creating custom copy constructor would help
As I demonstrated, you shouldn't define copy constructor for listPart - it should either be deleted or (in case of pre-C++ 11) private with no implementation provided. That's because copying std::promise is not defined (its copy constructor is deleted), so copying instance of listPart is meaningless in this case.
I was implementing (for training purpose) a Bubble Sort template function:
template<typename iterInput,
typename predicate>
void BubbleSort(iterInput first1,iterInput last1,predicate func)
{
bool swapped(false);
do
{
swapped = false;
iterInput begin = first1;
iterInput beginMinus = first1;
++begin;
for (;begin != last1; begin++,beginMinus++)
{
if (func(*beginMinus,*begin) )
{
std::swap(*beginMinus,*begin);
swapped = true;
}
}
}
while(swapped);
}
When I have realized that this function will not work for class with no assignment operator, like this one (forgive me for the bad name):
class NoCopyable
{
public:
explicit NoCopyable(int value) : value_(value) {}
NoCopyable(const NoCopyable& other) : value_(other.value_) {}
~NoCopyable() {}
bool operator<(const NoCopyable& other) { return value_ < other.value_; }
void setValue(int value) { value_ = value; }
std::ostream& print(std::ostream& os) const { return os << value_; }
private:
NoCopyable& operator=(const NoCopyable& other);
int value_;
};
std::ostream& operator<<(std::ostream& os, const NoCopyable& obj)
{
return obj.print(os);
}
struct PrintNoCopyable
{
void operator()(const NoCopyable& noCopyable) { std::cout << noCopyable << '\n'; }
};
The compiler raises this error Error 1 error C2248: 'NoCopyable::operator =' : cannot access private member declared in class 'NoCopyable'
So, I have slightly modify the code using instead of the std::swap function my version of the swap function, here is the code:
template<typename T1,
typename T2>
void noAssignmentSwap(T1& t1,T2& t2)
{
T1 temp(t1);
t1.~T1();
new (&t1) T1(t2);
t2.~T2();
new (&t2) T2(temp);
}
The code compiles and gives the right result. However I am not completely sure, I remember a Sutter's article that suggest you to avoid playing with the objects life time. The article just warns you by playing with fire without actually giving you any real reason. I can see problem in exception safety if the copy constructor of T1 or T2 can throw. However there is the same problem in the standard version if the assignment operator is allowed to throw.
Here the question, can you see any possible drawbacks in this version of swap?
Cheers
Apart from anything else, if a class does not have an assignment operator, its designer probably did not intend it to be swapped. If they did that, they probably disabled copy construction too, so your new swap function still won't work.
As for your assertion that Standard Library containers do not need assignment - that is true so long as you don't want to actually do anything useful with them. Does this code compile for you?
#include <vector>
using namespace std;
struct A {
private:
void operator=( const A &);
};
int main() {
vector <A> v;
v.push_back( A() );
v[0] = A(); // assignment needed here
}
I think it won't.
The difference is that when the assignment operator fails, you still have the same number of objects.
If you destroy one object and fail to create a new one, one object is lost! If it was part of a container, the container's state is probably also invalid.
You need a copy ctor instead of an assignment operator, but the two are sufficiently similar that at least in a typical case, you'll have both or you'll have neither. IOW, I don't think this generally accomplishes much.
I'd class it right along side the xor-swap trick: interesting, but generally useless.
It might be confusing to a future maintainer of the code.
I have a container (C++) on which I need to operate in two ways, from different threads: 1) Add and remove elements, and 2) iterate through its members. Clearly, remove element while iteration is happening = disaster. The code looks something like this:
class A
{
public:
...
void AddItem(const T& item, int index) { /*Put item into my_stuff at index*/ }
void RemoveItem(const T& item) { /*Take item out of m_stuff*/ }
const list<T>& MyStuff() { return my_stuff; } //*Hate* this, but see class C
private:
Mutex mutex; //Goes in the *Item methods, but is largely worthless in MyStuff()
list<T> my_stuff; //Just as well a vector or deque
};
extern A a; //defined in the .cpp file
class B
{
...
void SomeFunction() { ... a.RemoveItem(item); }
};
class C
{
...
void IterateOverStuff()
{
const list<T>& my_stuff(a.MyStuff());
for (list<T>::const_iterator it=my_stuff.begin(); it!=my_stuff.end(); ++it)
{
...
}
}
};
Again, B::SomeFunction() and C::IterateOverStuff() are getting called asynchronously. What's a data structure I can use to ensure that during the iteration, my_stuff is 'protected' from add or remove operations?
sounds like a reader/writer lock is needed. Basically, the idea is that you may have 1 or more readers OR a single writer. Never can you have a read and write lock at the same time.
EDIT: An example of usage which I think fits your design involves making a small change. Add an "iterate" function to the class which owns the list and make it templated so you can pass a function/functor to define what to do for each node. Something like this (quick and dirty pseudo code, but you get the point...):
class A {
public:
...
void AddItem(const T& item, int index) {
rwlock.lock_write();
// add the item
rwlock.unlock_write();
}
void RemoveItem(const T& item) {
rwlock.lock_write();
// remove the item
rwlock.unlock_write();
}
template <class P>
void iterate_list(P pred) {
rwlock.lock_read();
std::for_each(my_stuff.begin(), my_stuff.end(), pred);
rwlock.unlock_read();
}
private:
rwlock_t rwlock;
list<T> my_stuff; //Just as well a vector or deque
};
extern A a; //defined in the .cpp file
class B {
...
void SomeFunction() { ... a.RemoveItem(item); }
};
class C {
...
void read_node(const T &element) { ... }
void IterateOverStuff() {
a.iterate_list(boost::bind(&C::read_node, this));
}
};
Another Option would be to make the reader/writer lock publicly accessible and have the caller responsible for correctly using the lock. But that's more error prone.
IMHO it is a mistake to have a private mutex in a data structure class and then write the class methods so that the whole thing is thread safe no matter what the code that calls the methods does. The complexity that is required to do this completely and perfectly is way over the top.
The simpler way is to have a public ( or global ) mutex which the calling code is responsible for locking when it needs to access the data.
Here is my blog article on this subject.
When you return the list, return it enclosed in a class that locks/unlocks the mutex in its constructor/destructor. Something along the lines of
class LockedIterable {
public:
LockedIterable(const list<T> &l, Mutex &mutex) : list_(l), mutex_(mutex)
{lock(mutex);}
LockedIterable(const LockedIterable &other) : list_(other.list_), mutex_(other.mutex_) {
// may be tricky - may be wrap mutex_/list_ in a separate structure and manage it via shared_ptr?
}
~LockedIterable(){unlock(mutex);}
list<T>::iterator begin(){return list_.begin();}
list<T>::iterator end(){return list_.end();}
private:
list<T> &list_;
Mutex &mutex_;
};
class A {
...
LockedIterable MyStuff() { return LockedIterable(my_stuff, mutex); }
};
The tricky part is writing copy constructor so that your mutex does not have to be recursive. Or just use auto_ptr.
Oh, and reader/writer lock is indeed a better solution than mutex here.
Is there a way to code a write-only reference to an object? For example, suppose there was a mutex class:
template <class T> class mutex {
protected:
T _data;
public:
mutex();
void lock(); //locks the mutex
void unlock(); //unlocks the mutex
T& data(); //returns a reference to the data, or throws an exception if lock is unowned
};
Is there a way to guarantee that one couldn't do this:
mutex<type> foo;
type& ref;
foo.lock();
foo.data().do_stuff();
ref = foo.data();
foo.unlock();
//I have a unguarded reference to foo now
On the other hand, is it even worth it? I know that some people assume that programmers won't deliberately clobber the system, but then, why do we have private variables in the first place, eh? It'd be nice to just say it's "Undefined Behavior", but that just seems a little bit too insecure.
EDIT: OK, i understand the idea of a setter routine, but how would this be accomplished?
mutex<vector<int> > foo;
foo.lock();
for (int i=0; i < 10; i++) {
foo.data().push_back(i);
}
foo.unlock();
Using a set routine would require a copy for each write:
mutex<vector<int> > foo;
foo.lock();
for (int i=0; i < 10; i++) {
vector<int> copy = foo.read();
copy.push_back(i);
foo.write(copy);
}
though you could trivially optimize in this specific case, if, say, several different threads are all pushing elements, and maybe even erasing a few, this can become quite a bit of excess memory copying (i.e. one per critical section).
Yes, you can create a wrapper class that becomes invalidated when unlock is called and return the wrapper, instead of returning the reference, and you can overload its assignment operator to assign to the reference. The trick is that you need to hang onto a reference to the wrapper's internal data, so that when unlock is called, prior to releasing the lock, you invalidate any wrappers that you have created.
The common way to differentiate between getters and setters is by the const-ness of the object:
template <class T> class mutex {
public:
mutex();
void lock();
void unlock();
T& data(); // cannot be invoked for const objects
const T& data() const; // can be invoked for const objects
protected:
T _data;
};
Now, if you want to have read-only access, make the mutex const:
void read_data(const mutex< std::vector<int> >& data)
{
// only const member functions can be called here
}
You can bind a non-const object to a const reference:
// ...
mutex< std::vector<int> > data;
data.lock();
read_data(data);
data.unlock();
// ...
Note that the lock() and unlock() functions are inherently unsafe in the face of exceptions:
void f(const mutex< std::vector<int> >& data)
{
data.lock();
data.data().push_back(42); // might throw exception
data.unlock(); // will never be reached in push_back() throws
}
The usual way to solve this is RAII (resource acquisition is initialization):
template <class T> class lock;
template <class T> class mutex {
public:
mutex();
protected:
T _data;
private:
friend class lock<T>;
T& data();
void lock();
void unlock();
};
template <class T> class lock {
public:
template <class T> {
lock(mutex<T>& m) m_(m) {m_.lock();}
~lock() {m_.unlock();}
T& data() {return m_.data();}
const T& data() const {return m_.data()}
private:
mutex<T>& m_;
};
Note that I have also moved the accessor functions to the lock class, so that there is no way to access unlocked data.
You can use this like this:
void f(const mutex< std::vector<int> >& data)
{
{
lock< std::vector<int> > lock_1(data);
std::cout << lock1.data()[0]; // fine, too
lock1.data().push_back(42); // fine
}
{
const lock< std::vector<int> > lock_2(data); // note the const
std::cout << lock1.data()[0]; // fine, too
// lock1.data().push_back(42); // compiler error
}
}
You could encapsulate the data as private and expose a write routine. Within that routine you could lock your mutex, giving you similar behavior to what you are shooting for.
You can use a member function as the following:
void set_data(const T& var);
This is how write-only access is applied in C++.
No. There is no way to guarantee anything about reading and writing memory in unsafe languages like C++, where all the memory is treated like one big array.
[Edit] Not sure why all the downvotes; this is correct and relevant.
In safe languages, such as Java or C#, you can certainly guarantee that, for instance, properly-implemented immutable types will stay immutable. Such a guarantee can never be made in C++.
The fear is not so much malicious users as it is accidental invalid-pointers; I have worked on C++ projects where immutable types have been mutated due to an invalid pointer in completely unrelated code, causing bugs that are extremely difficult to track down. This guarantee - which only safe languages can make - is both useful and important.