I have a resource that is shared between two concurrent threads. The resource contains a vector that both threads need to read and write to. Hence, I make access to the vector exclusive through a mutex. So far so good, sharing of resource works well without any problems.
However, the problem starts when I try to write a copy constructor for sharedResource as follows.
class sharedResource{
public:
sharedResource(){}
sharedResource(const sharedResource &other) {
vec = other.GetVec();
}
std::vector<int> GetVec() const {
std::lock_guard<std::mutex> lock(vecMutex); // Gives error
return vec;
}
private:
std::vector<int> vec;
std::mutex vecMutex;
};
int main()
{
sharedResource bacon1;
sharedResource bacon2 = bacon1;
return 0;
}
For this code, I get error
error C2664: 'std::lock_guard<std::mutex>::lock_guard(const std::lock_guard<std::mutex> &)' : cannot convert argument 1 from 'const std::mutex' to 'std::mutex &'
Could you please explain why am I getting the error and if there is a way to use the mutex without getting the compiler error.
If all else fails, I am going to create a thread unsafe GetVec2 member function, that will return vec without going through lock guard. But I would like to avoid this eventuality.
std::vector<int> GetVec2() const {
return vec;
}
This happens because getVec() is a const method but vecMutex is not mutable. You should either make getVec() non-const so it can modify (acquire) the mutex, or make the mutex mutable so it can be acquired by const methods too. I'd probably do the latter.
The quick answer is to make the vecMutex mutable.
mutable std::mutex vecMutex;
There is another non-standard issue with your code. Your default and copy constructor are declared incorrectly. It should be this:
sharedResource(){}
sharedResource(const sharedResource &other)
{
vec = other.GetVec();
}
You're also missing assignment operator.
Related
I'm not sure why this is happening when I add a mutex member to myClass(in this example mu):
Error C2661 "'std::tuple<
void (__thiscall MyNameSpace::myClass::* )(void),MyNameSpace::myClass>::tuple': no overloaded function takes 2 arguments include\memory 2438
namespace MyNameSpace{
class myClass{
shared_ptr<myClass2> property;
mutex mu;
public:
myClass(shared_ptr<myClass2> arg):property(std::move(arg)) {
}
void Run(){
...........
}
}
class myClass2{
public:
myClass2(std::string str) {
trace(str);
}
}
}
int main(){
shared_ptr<myClass2> new_obj(new myClass2("somthing"));
thread(&myClass::Run, myClass(new_obj)).join();
.......other stuff.....
}
and How can i overcome this?
It is a compilation error, not a memory error.
Note that std::mutex is not copiable. So, the class containing it becomes non-copiable as well.
I guess (as you do not show the relevant code) that you attempt to copy an instance of myClass, and that causes the above compilation error.
In particular, you can search places in your code, where you pass or return myClass instances by value.
UPDATE: As pointed out by #NathanOliver, such a place in the above snippet is:
thread(&myClass::Run, myClass(new_obj))
where a temporary myClass is created.
Here's my problem.
I have a structure like this.
struct threadInfo
{
std::condition_variable cv;
std::mutex m;
int priorityLevel;
};
When building my code I get this error
Error C2280 threadInfo::threadInfo(const threadInfo &): attempting
to reference a deleted function PriorityListMutex
From my understanding it means that the constructor for threadInfo is called and it tries to copy the mutex which is not possible.
I don't have much experience with c++ and even though I somewhat understand what is happening, I'm not sure how to attempt to fix this. Any help would be great!
Here is the code that uses ThreadInfo
threadInfo info;
info.priorityLevel = priority;
priorityListMutex.lock();
for (std::list<threadInfo>::iterator it = threadList.begin(); it != threadList.end(); it++)
{
if ((*it).priorityLevel < info.priorityLevel)
{
threadList.insert(it, info);
break;
}
else if (it == threadList.end())
{
threadList.push_back(info);
break;
}
}
priorityListMutex.unlock();
std::unique_lock<std::mutex> lock(info.m);
info.cv.wait(lock);
I guess the structure is being copied somewhere in there, but I'm completely missing where.
You can solve your problem by avoiding copies and emplacing the structs directly in the list. This does require a custom constructor though. I've shortened your code sample to only show the emplacing portion:
#include <mutex>
#include <condition_variable>
#include <list>
struct threadInfo
{
explicit threadInfo(int prio) : priorityLevel(prio) {}
std::condition_variable cv;
std::mutex m;
int priorityLevel;
};
int main()
{
std::list<threadInfo> threadList;
int priorityLevel = 0;
for (std::list<threadInfo>::iterator it = threadList.begin(); it != threadList.end(); it++)
{
if ((*it).priorityLevel < priorityLevel)
{
threadList.emplace(it, priorityLevel);
break;
}
else if (it == threadList.end())
{
threadList.emplace_back(priorityLevel);
break;
}
}
return 0;
}
In the Standard C++ Library, classes related to threading, like mutex, do not have a copy constructor.
When an assignment involves two objects, like
Class b(10);
Class a = b;
At the second line, we try to create an object initializing from another object. This makes the compiler look for a copy constructor, a constructor developed specifically for this purpose.
Since having two identical copy of a mutex is not good, the library doesn't use such method for thread related classes.
Usually compilers create default copy-constructors in case they are needed, but when a class a property of this type it cannot do so, so it gives you and error.
To solve, you will have to explicitly define a copy constructor and handle manually. Beware, you should keep in mind that things related to threads like mutex and cv should not exists in more than one copy.
The copy constructor of mutex is deleted explicitly. You can't copy a mutex, however, if what you are doing is moving rather than copying (e.g. you won't need the old value of you threadInfo object) than you can move the mutex using std::move and writing a move constructor for your threadInfo object.
However, a move constructor can cause hard to spot bug so I wouldn't recommend that. A more straight forward way would be to wrap your "info" object in a pointer and use that. You can achieve that as such:
auto info = std::make_shared<threadInfo>{};
info->priorityLevel = priority;
priorityListMutex.lock();
for (std::list<std::shared_ptr<threadInfo>>::iterator it = threadList.begin(); it != threadList.end(); it++)
{
if ((*it).priorityLevel < info->priorityLevel)
{
threadList.insert(it, info);
break;
}
else if (it == threadList.end())
{
threadList.push_back(info);
break;
}
}
priorityListMutex.unlock();
std::unique_lock<std::mutex> lock(info.m);
info->cv.wait(lock);
Do note however, that in this case I'm using a shared_ptr, which is the "easiest" way to do this since it won't break anything but probably not want you want to do, what you most likely want to do, is give the 'threadList' object ownership of your info object. in which case you would declare it as a unique_ptr:
auto info = std::make_uniq<threadInfo>{};
and move it into the threadList:
threadList.insert(it, std::move(info));
I'm trying to create a wrapper for an std::vector (or any other container from STL, if possible) that can "lock" and "unlock" the const state of a vector that it's holding.
For example, if I create an object of that wrapper, I want to be able to do something like this:
int main()
{
ConstLockVectorWrapper<int> myWrapper(std::vector<int>{}); // Here I pass an empty vector in the constructor parameters,
// which means that my wrapper will be holding an empty vector
// By default the vector inside my wrapper is not locked,
// I can change its size and the values that it holds
myWrapper.get().push_back(10); // ok
myWrapper.get().push_back(20); // ok
myWrapper.get().at(0) = 5; // ok
print(myWrapper.get()); // Prints 5 20
myWrapper.lock(); // Now I made the vector inside my wrapper unchangable
myWrapper.get().push_back(30); // error, the vector is locked
myWrapper.get().at(0) = 55; // error
print(myWrapper.get()); // ok
myWrapper.unlock(); // Now I can change my vector's size and its values again
_getch();
return 0;
}
The only solution (that's not working, unfortunately) I've got, is to create a const reference (const std::vector<T> &) and a regular reference (td::vector<T> &) inside a wrapper class, and bound them to the main vector in our wrapper class.
So, this is what I've done:
template <typename T>
class ConstLockVectorWrapper {
public:
ConstLockVectorWrapper(const std::vector<T> & vec)
: wrappedVector(vec), wrappedVectorRef(wrappedVector), wrappedVectorConstRef(wrappedVector), constLock(false)
{}
void lock()
{
if (constLock) // if the vector is already locked, we just exit the function
return;
// else we lock the vector
constLock = true;
}
void unlock()
{
if (!constLock) // if the vector is already unlocked (changable), we just exit the function
return;
// else we unlock the vector
constLock = false;
}
return_type get() // I need to return a const std::vector<T> & if constLock == true, and std::vector<T> & otherwise, what return type should I put in here?
{
if (constLock)
return wrappedVectorConstRef;
else
return wrappedVectorRef;
}
private:
bool constLock;
std::vector<T> wrappedVector;
// refs
std::vector<T> & wrappedVectorRef;
const std::vector<T> & wrappedVectorConstRef;
};
Of course, it doesn't work. Just because I don't know what to put in the return type of my get() fucntion.
I've tried using trailing return type, didn't work:
template <typename T>
class ConstLockVectorWrapper {
public:
// ...
private:
bool constLock;
std::vector<T> wrappedVector;
// refs
std::vector<T> & wrappedVectorRef;
const std::vector<T> & wrappedVectorConstRef;
public:
auto get() -> decltype((constLock ? wrappedVectorConstRef : wrappedVectorRef))
{
if (constLock)
return wrappedVectorConstRef;
else
return wrappedVectorRef;
}
};
I can't come up with any solution that will actually work, because I'm not so good at C++ yet.
So I'm asking for your help with my problem. Any suggestions or hints to solve this problem would be appreciated!
Thanks
PS
My main goal is to make my wrapper container-type-independent, so it can "lock" and "unlock" the const state of the container it's holding, independently of its type.
And here's the print() function I used in the first code snippet:
template <typename Container>
void print(const Container & c)
{
for (const auto & var : c)
std::cout << var << std::endl;
}
Fundamentally, a method always returns the same thing. The same type. Every time. It's not possible, in C++, to have a method sometimes return one type, and another type at other times. C++ does not work this way.
So, the initial approach would be to have get() return a proxy object with a state. Using, roughly, the same classes and names from your question:
class return_type {
bool is_const;
std::vector<T> &wrapped_vec;
public:
return_type(bool is_constArg,
std::vector<T> &wrapped_vecArg)
: is_const(is_constArg), wrapped_vec(wrapped_vecArg)
{
}
void push_back(T &&t)
{
if (is_const)
throw std::runtime_error(); // Or, whatever...
wrapped_vec.push_back(std::forward<T>(t));
}
// return_type will have to implement, and baby-sit all other
// methods you wish to invoke on the underlying vector.
};
return_type get()
{
return return_type(constLock);
}
This is simple, but crude and somewhat tedious. You would have to implement every std::vector method you need to use in the return_type proxy.
A better approach would be to take advantage of C++11 lambdas. This will avoid the need to reimplement every wheel, at an expense of some additional code bloat. But, big deal. RAM is cheap, these days. Instead of get() and return_type, you will now be implementing two template methods in your wrapper: get_const() and get_mutable(). Each one of them takes a lambda parameter and invokes it and, if all goes well, passing it the wrapped vector as an argument:
template<typename lambda>
void get_mutable(lambda &&l)
{
if (constLock)
throw std::runtime_error(); // Or, whatever...
l(wrapped_vec);
}
template<typename lambda>
void get_const(lambda &&l)
{
l(const_cast<const std::vector<T> &>(wrapped_vec));
}
The only thing you now need to decide is whether you need access a mutable or a constant vector, and pick the right getter:
myWrapper.get_mutable( [&](std::vector<int> &v) { v.push_back(10); } );
get_mutable() throws an exception if the vector is locked at this time. Otherwise it passes the vector to your lambda. Your lambda does whatever the heck it wants with it, which can be push_back(), or anything else, then returns.
But if you only need read-only access to the vector, use get_const():
int s;
myWrapper.get_const( [&](const std::vector<int> &v) { s=v.size(); } );
Note that get_const() takes care to const_cast the vector, before invoking the lambda, so the lambda will not be able to modify it. This will be enforced at compile-time.
With some additional work, it would also be possible to clean this up a little bit, and have the getter also return whatever lambda returns to the caller, making it possible to do something like this:
int s=myWrapper.get_const( [&](const std::vector<int> &v) { return v.size(); } );
It's possible to have get_const() and get_mutable() be smart enough to figure out if the lambda returns something, and happily pass it back to the caller, whatever it is. And how to do that, I suppose, will have to be another question on stackoverflow.com
P.S. If you don't have C++11, you can just have get_const() and get_mutable() return the wrapped vector (with get_mutable() verifying that it's not locked). This really accomplishes the same thing. The key point is that due to the way that C++ works, you will have to disambiguate, in advance, whether you need constant or mutable access.
I was working on a similar problem a while back. In multithreaded environment sometimes its more efficient to have different types of lock depending on whether you are reading or writing. But the locking is entirely cooperative. It is possible to obtain a read-only lock but still accidentally write to the object.
One solution I am exploring is, instead of obtaining a read-only lock from an object, getting a read-only wrapper of my object so that not only is the object read-only locked it is also only possible to call read-only (const) methods on the object.
The basic wrapper I used was something like this:
template<typename T>
class ConstWrapper
{
T& v;
public:
ConstWrapper(T& v): v(v) {}
T const& operator* () const { return v; } // return const reference
T const* operator->() const { return &v;} // return const pointer
};
By overloading the * and -> operators you get a kind of pass through ability to call the enclosed objects methods - but using pointer semantics (though its not a pointer).
std::vector<int> v {1, 2, 3, 4}; // not const
ConstWrapper<std::vector<int>> cv(v); // const wrapper
std::cout << cv->at(0) << '\n'; // okay at() is a const method
cv->push_back(8); // ILLEGAL!! push_back() is not a const method
In the following code the bad method fails to compile, but the good method does not. Why is providing the explicit reference to this making a difference here?
#include <mutex>
class Foo
{
private:
std::mutex lock_;
public:
Foo() = default;
~Foo() = default;
void bad();
void good();
};
void Foo::bad()
{
std::lock_guard<std::mutex>(lock_);
}
void Foo::good()
{
std::lock_guard<std::mutex>(this->lock_);
}
int main()
{
return 0;
}
compile error:
test.cpp: In member function ‘void Foo::bad()’:
test.cpp:18:36: error: no matching function for call to ‘std::lock_guard<std::mutex>::lock_guard()’
std::lock_guard<std::mutex>(lock_);
You can play with the ideone if you want.
This is an instance of the most vexing parse. The parentheses here don't do what you think they do. This:
std::lock_guard<std::mutex>(lock_);
is equivalent to:
std::lock_guard<std::mutex> lock_;
which should make it clear why what you're trying to do won't compile, and why you're getting the compile error you're getting. What you need to do is provide a name for the lock_guard:
std::lock_guard<std::mutex> _(lock_);
The good version works because the this-> qualification prevents the name from being able to be treated as an identifier.
Note: lock_ is a std::mutex and not any kind of lock, which makes it a very confusing name. You should name it something more reflective of what it is. Like mutex_.
If you declare your lock_guard correctly, they both work:
void Foo::bad()
{
std::lock_guard<std::mutex> x{lock_};
}
void Foo::good()
{
std::lock_guard<std::mutex> y{this->lock_};
}
Using a temporary is almost useless, because the lock gets released immediately. Correct usage is to declare a local variable with automatic lifetime.
You need to actually create a variable, for example
std::lock_guard<std::mutex> lg(lock_);
I´m using a struct to support a list of Windows SOCKET´s:
struct ConnectedSockets{
std::mutex lock;
std::list<SOCKET> sockets;
};
When i try to compile this (Visual Studio 2012) i get the following error:
"Error C2248: std::mutex::operator = cannot access 'private' member declared in class 'std::mutex'"
Does anybody know how to fix this?
A std::mutex is not copyable, so you will need to implement the operator= for ConnectedScokets yourself.
I presume you want to keep a mutex per instance of ConnectedSockets, so this should be enough:
ConnectedSockets& operator =( ConnectedSockets const& other )
{
// keep my own mutex
sockets = other.sockets; // maybe sync this?
return *this;
}
Root cause has nothing about sockets. std::mutex is not copyable, so compiler fails to generate default assignment operator (which is memberwise) for ConnectedSockets struct. You need to instruct compiler to delete assignment operator (declare it using = delete specifier) or implement it manually, e.g. ignoring mutex copying.
// To make ConnectedSockets explicitly non-copyable and get more reasonable
// compiler error in case of misuse
struct ConnectedSockets
{
std::mutex lock;
std::list<SOCKET> sockets;
ConnectedSockets& operator=(const ConnectedSockets&) = delete;
};
// To make ConnectedSockets copyable but keep mutex member intact
struct ConnectedSockets
{
std::mutex lock;
std::list<SOCKET> sockets;
ConnectedSockets& operator=(const ConnectedSockets& i_rhs)
{
// Need locking? Looks like it can be problem here because
// mutex:lock() is not const and locking i_rhs wouldn't be so easy
sockets = i_rhs.sockets;
return *this;
}
};