Can a class object be created as an lvalue-only? - c++

A well-known problem with std::lock_guard (and its relatives) is that it does not work the way as expected when only a temporary object is created.
For example:
std::mutex mtx;
std::lock_guard<std::mutex> {mtx} // temporary object, does not lock the entire scope
std::lock_guard<std::mutex> lck{mtx} // correct
I tried reference qualifiers to create a replacement that prevents a temporary object from being created (at compile time). The following code is a futile attempt:
#include <mutex>
template<typename T>
struct my_lock {
T &mtx;
my_lock(T &t) : mtx{t} { lock(); }
~my_lock() { unlock(); }
void lock() & { mtx.lock(); };
void unlock() & { mtx.unlock(); };
};
std::mutex mtx;
int main()
{
my_lock<std::mutex> {mtx}; // A
my_lock<std::mutex lck{mtx}; // B
}
This does not work, so the question becomes:
Is it possible to write the class in such a way that the compiler rejects A and accepts B ?

if you can use c++17, you can use [[nodiscard]] attribute with factory function.
class [[nodiscard]] my_lock{
my_lock()=default;
friend my_lock lock();
};
[[nodiscard]] my_lock lock(){return {};}
int main(){
{ lock(); } //warning for discard return value
{ auto l = lock();}
}

Let me reinterpret your question, instead of:
Is it possible to write the class in such a way that the compiler rejects A and accepts B ?
I'm gonna read this as
Is it possible for my compiler to reject A and accept B?
Yes, this is possible depending on the compiler without requiring to write your own classes. I'm very familiar with clang, however, similar checks will exist in other compilers or static analysers.
For clang, -Wunused-value -Werror will do the job. The first activates the warning, the second promotes it to an error.
Personally, I'm in favor to enable all warnings and explicitly disable those you have a reason not to comply to, including documentation on why.

Related

Mutex that works across std implementations

Related to this question, I need a mutex that works across std implementations, or a way to atomically write and read a pointer. One thread is spawned by code compiled with mingw-w64 and the other one is Visual Studio 2019 code in a static/dynamic library.
Export from your main executable (mingw-w64) to your DLL (VC++) - compiled with separate compilers - a synchronization/mutex "handle" (an opaque pointer, typically, though it can be an index into something too) and a pair of C-style functions (if you want, you can wrap them into classes like std::mutex and std::lock, exposing the same API - that'd be the safest thing to do) lock and unlock that take that handle. They can be just as bare as that, or they might include additional functionality like timeout, or try-lock - these are quite useful but not required. You can also export handle_t create() and void delete(handle_t handle) functions.
The point is that the sync object itself (the mutex or whatever) is always manipulated by those indirection functions to avoid errors in usage, and these functions are, depending on the compiler (that can easily be detected by the preprocessor), backed by compiler-specific atomic operation intrinsics or CRT functions, like the perfectly fitting InterlockedCompareExchange (it works under mingw-w64 too) and its Visual C++ specific compiler intrinsic variant, or GCC's __atomic (more specifically, __atomic_compare_exchange).
struct imutex {
virtual void lock() = 0;
virtual void unlock() = 0;
virtual ~imutex(){}
};
template<class M>
struct imp_mutex: imutex {
M m;
void lock() final override { m.lock(); }
void unlock() final override { m.unlock(); }
};
struct mymutex {
using up=std::unique_ptr<imutex, void(*)(imutex*)>;
mymutex( up m_in ):m(std::move(m_in)){}
mymutex():mymutex(up(new imp_mutex<std::mutex>{}, [](imutex* m){ delete m; })) {}
void lock(){ m->lock(); }
void unlock(){ m->unlock(); }
mymutex(mymutex&&)=delete;
private:
up m;
};
this assumes ABI compatibility of vtables and std::unique_ptr, which is plausible.
If not, replace unique ptr with something custom, and replace the virtual methods with function pointers taking a void pointer.
The point is, the mutex is created and destroyed in one library's code.
Here is a pure function pointer one. It relies that a struct containing two-three ptrs has the same layout, and that thr C calling convention is the same.
Whichever library makes the mymutex, both can then use it.
struct imutex_vtable {
void (*lock)(void*) = 0;
void (*unlock)(void*) = 0;
void (*dtor)(void*)=0;
};
template<class M>
imutex_vtable const* get_imutex_vtable(){
static const imutex_vtable vtable = {
[](void* m){ static_cast<M*>(m)->lock(); },
[](void* m){ static_cast<M*>(m)->unlock(); },
[](void* m){ delete static_cast<M*>(m); }
};
return &vtable;
}
struct mymutex {
mymutex( imutex_vtable const* vt, void* pm ):vtable(vt), pv(pm){}
template<class M>
explicit mymutex(std::unique_ptr<M> m):mymutex( get_imutex_vtable<M>(), m.release() ) {}
mymutex():mymutex(std::make_unique<std::mutex>()) {}
void lock(){ vtable->lock(pv); }
void unlock(){ vtable->unlock(pv); }
~mymutex(){ vtable->dtor(pv); }
mymutex(mymutex&&)=delete;
private:
imutex_vtable const* vtable=0;
void* pv=0;
};
This is basically implementing a simple case of C++ interface inheritance using C-like implementation, then wrapping it up in classes and templates so the user won't notice.

Bind mutex to object

Given the following example code:
int var;
int mvar;
std::mutex mvar_mutex;
void f(){
mvar_mutex.lock();
mvar = var * var;
mvar_mutex.unlock();
}
I want to express that mvar_mutex is bound to the variable mvar and protects only that variable. mvar_mutex should not protect var because it is not bound to it. Hence the compiler would be allowed to transform the above code into the below code:
int var;
int mvar;
std::mutex mvar_mutex;
void f(){
int r = var * var; //possible data race created if binding is not known
mvar_mutex.lock();
mvar = r;
mvar_mutex.unlock();
}
This might reduce contention on the lock as less work is being done while holding it.
For int this can be done using std::atomic<int> mvar; and removing mvar_mutex, but for other types such as std::vector<int> this is not possible.
How do I express the mutex-variable binding in a way that C++ compilers understand it and do the optimization? It should be allowed to reorder any variable up or down across mutex boundaries for any variable that is not bound to that mutex
Since the code is being generated using clang::ASTConsumer and clang::RecursiveASTVisitor I am willing to use non-standard extensions and AST manipulations as long as clang (ideally clang 4.0) supports them and the resulting code does not need to be elegant or human-readable.
Edit since this seems to be causing confusion: The above transformation is not legal in C++. The described binding of mutex to variable doesn't exist. The question is about how to implement that or achieve the same effect.
If you wish to achieve that the std::mutex will only be held until an operation is performed on the protected object, you can write a wrapper class as follows:
#include <cstdio>
#include <mutex>
template<typename T>
class LockAssignable {
public:
LockAssignable& operator=(const T& t) {
std::lock_guard<std::mutex> lk(m_mutex);
m_protected = t;
return *this;
}
operator T() const {
std::lock_guard<std::mutex> lk(m_mutex);
return m_protected;
}
/* other stuff */
private:
mutable std::mutex m_mutex;
T m_protected {};
};
inline int factorial(int n) {
return (n > 1 ? n * factorial(n - 1) : 1);
}
int main() {
int var = 5;
LockAssignable<int> mvar;
mvar = factorial(var);
printf("Result: %d\n", static_cast<int>(mvar));
return 0;
}
In the example above the factorial will be calculated in advance and the m_mutex will be acquired only when the assignment or the implicit conversion operator being called on mvar.
Assembly Output
For the primitive data types you can use std::atomic with std::memory_order_relaxed.
The documentation states that:
there are no synchronization or ordering constraints imposed on other
reads or writes, only this operation's atomicity is guaranteed
In the following example, the atomicity of the assignation is guaranteed, but the compiler should be able to move the operations.
std::atomic<int> z = {0};
int a = 3;
z.store(a*a, std::memory_order_relaxed);
For objects, I thought of several solutions, but:
There is no standard way to remove ordering requirements from std::mutex.
It is not possible to create a std::atomic<std::vector>.
It is not possible to create a spinlock using std::memory_order_relaxed (see the example).
I have found some answers that state that:
If the function is not visible in the compilation unit, the compiler generates a barrier because it does not know which variables it uses.
If the function is visible and there is a mutex, the compiler generates a barrier.
For example, see this and this
So, in order to express that mvar_mutex is bound to the variable, you can use some classes as stated by the other answers but I do not think it is possible to fully allow the reordering of the code.
I want to express that mvar_mutex is bound to the variable mvar and protects only that variable.
You can't do this. A mutex actually guards the critical region of machine instructons between the acquisition and release. Only by convention is that associated with a particular instance of shared data.
To avoid doing unnecessary steps inside the critical region, keep the critical regions as simple as possible. In a critical region, only with local variables which the compiler can "see" are obviously not shared with other threads, and with one set of shared data belonging to that mutex. Try not to access other data in the critical region that might be suspected of being shared.
If you could have your proposed language feature, it would only introduce the possibility of error into a program. All it does is take code which is now correct, and make some of it incorrect (in exchange for the promise of some speed: that some code stays correct and is faster, because extraneous computations are moved out of the critical region).
It's like taking a language which already has a nice order of evaluation, in which a[i] = i++ is well defined, and screwing it up with unspecified evaluation order.
How about a locked var template ?
template<typename Type, typename Mutex = std::mutex>
class Lockable
{
public:
Lockable(_Type t) : var_(std::move(t));
Lockable(_Type&&) = default;
// ... could need a bit more
T operator = (const T& x)
{
std::lock_guard<Lockable> lock(*this);
var_ = x;
return x;
}
T operator *() const
{
std::lock_guard<Lockable> lock(*this);
return var_;
}
void lock() const { const_cast<Lockable*>(this)->mutex_.lock(); }
void unlock() const { const_cast<Lockable*>(this)->mutex_.unlock().; }
private:
Mutex mutex_;
Type var_;
};
locked by assignment operator
Lockable<int>var;
var = mylongComputation();
Works great with lock_guard
Lockable<int>var;
std::lock_guard<Lockable<int>> lock(var);
var = 3;
Practical on containers
Lockable<std::vector<int>> vec;
etc...
You can use folly::Synchronized to make sure that the variable is only accessed under a lock:
int var;
folly::Synchronized<int> vmar;
void f() {
*mvar.wlock() = var * var;
}
I want to express that mvar_mutex is bound to the variable mvar and
protects only that variable.
This is not how a mutex works. It doesn't "bind" to anything in order to protect it. You are still free to access this object directly, in complete disregard with any sort of thread safety whatsoever.
What you should do is hide away the "protected variable" so that it is not directly accessible at all, and write an interface that manipulates it that goes through the mutex. This way you ensure that access to the underlying data is protected by that mutex. It can be a single object, it can be a functional group of objects, it can be a collection of many objects, mutexes and atomics, designed to minimize blocking.

Pointer-to-Function and Pointer-to-Object Semantics

I'm having issues with getting a partially-qualified function object to call later, with variable arguments, in another thread.
In GCC, I've been using a macro and typedef I made but I'm finishing up my project an trying to clear up warnings.
#define Function_Cast(func_ref) (SubscriptionFunction*) func_ref
typedef void(SubscriptionFunction(void*, std::shared_ptr<void>));
Using the Function_Cast macro like below results in "warning: casting between pointer-to-function and pointer-to-object is conditionally-supported"
Subscriber* init_subscriber = new Subscriber(this, Function_Cast(&BaseLoaderStaticInit::init), false);
All I really need is a pointer that I can make a std::bind<function_type> object of. How is this usually done?
Also, this conditionally-supported thing is really annoying. I know that on x86 my code will work fine and I'm aware of the limitations of relying on that sizeof(void*) == sizeof(this*) for all this*.
Also, is there a way to make clang treat function pointers like data pointers so that my code will compile? I'm interested to see how bad it fails (if it does).
Relevant Code:
#define Function_Cast(func_ref) (SubscriptionFunction*) func_ref
typedef void(SubscriptionFunction(void*, std::shared_ptr<void>));
typedef void(CallTypeFunction(std::shared_ptr<void>));
Subscriber(void* owner, SubscriptionFunction* func, bool serialized = true) {
this->_owner = owner;
this->_serialized = serialized;
this->method = func;
call = std::bind(&Subscriber::_std_call, this, std::placeholders::_1);
}
void _std_call(std::shared_ptr<void> arg) { method(_owner, arg); }
The problem here is that you are trying to use a member-function pointer in place of a function pointer, because you know that, under-the-hood, it is often implemented as function(this, ...).
struct S {
void f() {}
};
using fn_ptr = void(*)(S*);
void call(S* s, fn_ptr fn)
{
fn(s);
delete s;
}
int main() {
call(new S, (fn_ptr)&S::f);
}
http://ideone.com/fork/LJiohQ
But there's no guarantee this will actually work and obvious cases (virtual functions) where it probably won't.
Member functions are intended to be passed like this:
void call(S* s, void (S::*fn)())
and invoked like this:
(s->*fn)();
http://ideone.com/bJU5lx
How people work around this when they want to support different types is to use a trampoline, which is a non-member function. You can do this with either a static [member] function or a lambda:
auto sub = new Subscriber(this, [](auto* s){ s->init(); });
or if you'd like type safety at your call site, a templated constructor:
template<typename T>
Subscriber(T* t, void(T::*fn)(), bool x);
http://ideone.com/lECOp6
If your Subscriber constructor takes a std::function<void(void))> rather than a function pointer you can pass a capturing lambda and eliminate the need to take a void*:
new Subscriber([this](){ init(); }, false);
it's normally done something like this:
#include <functional>
#include <memory>
struct subscription
{
// RAII unsubscribe stuff in destructor here....
};
struct subscribable
{
subscription subscribe(std::function<void()> closure, std::weak_ptr<void> sentinel)
{
// perform the subscription
return subscription {
// some id so you can unsubscribe;
};
}
//
//
void notify_subscriber(std::function<void()> const& closure,
std::weak_ptr<void> const & sentinel)
{
if (auto locked = sentinel.lock())
{
closure();
}
}
};

How to use std::lock_guard on a class member mutex

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_);

How could I avoid this raw pointer with this OpenMP critical section?

I have a std::deque<std::reference_wrapper<MyType>> mydeque. I need a function that returns the front value (as a plain reference) and pops it from the queue. As std::deque are not thread safe, access should be protected (I'm using OpenMP).
I came up with the ugly code below. It looks very bad having such advanced structures and then falling back to a raw pointer.
MyType & retrieve() {
MyType* b;
#pragma omp critical(access_mydeque)
{
b = &(mydeque.front().get());
mydeque.pop_front();
}
return *b;
}
The problem is that I cannot return within the critical section, but I also cannot declare a reference(_wrapper) before the critical section (because it must be assigned to something)... Is there a way to solve this?
Any solution I can think of involves using an omp_lock_t instead of the critical construct and a RAII class managing the omp_lock_t ownership:
class LockGuard {
public:
explicit LockGuard(omp_lock_t& lock) : m_lock(lock){
omp_set_lock(&m_lock);
}
~LockGuard() {
omp_unset_lock(&m_lock);
}
private:
omp_lock_t& m_lock;
};
Then you can either modify the code you already have into something like:
MyType & retrieve() {
LockGuard guard(mydeque_lock);
auto b = mydeque.front();
mydeque.pop_front();
return b;
}
or better, write your own thread-safe container that aggregates the lock and the std::deque:
template<class T>
class MtLifo {
public:
MtLifo() {
omp_init_lock(&m_lock);
}
typename std::deque<T>::reference front_and_pop() {
LockGuard guard(m_lock);
auto b = m_stack.front();
m_stack.pop_front();
return b;
}
void push_front(const T& value) {
LockGuard guard(m_lock);
m_stack.push_front(value);
}
~MtLifo() {
omp_destroy_lock(&m_lock);
}
private:
std::deque<T> m_stack;
omp_lock_t m_lock;
}
You could simply use TBB's parallel data structures https://software.intel.com/en-us/node/506076 (though since there is no concurrent_deque they may not be perfect for you :-( ).
They do not require that you also use TBB to describe the parallelism aspects of your code, so can be mixed into an OpenMP code. (Of course, since you're using C++ you might find TBB's approach to scalable, composable, parallelism more friendly than OpenMP's, but that's a separable decision).