Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Local static variable shared between all instantiations of a generic lambda expression

Tags:

c++

lambda

c++14

I have some code where a non-generic lamba expression has a local static variable: a mutex for a critical section. Something that can be simplified to:

int i = 0;
auto lambda = [&i](int &v)
{
    static std::mutex mutex;
    std::lock_guard<std::mutex> lock(mutex);
    /* critical section with v and i */};
}

Now, the critical section implemented in this lambda expression could be reused verbatim for other types than int & and I would have liked a change as simple as replacing int with auto in the declarator, like this:

auto lambda = [&i](auto &v)

Unfortunately, if I do this, lambda(int&) and lambda(float&) won't share the same local static variable anymore, which will defeat the lock in the critical section.

What would be the simplest change in the code that would meet all these requirements:

  • provide the genericity that I need; and
  • ensure that I have a single mutex shared across all instantiations of the critical section; and
  • does not expose the mutex to public view

A solution that would work would be to replace the lambda expression with a class with a template method, something like this:

class Lambda
{
public:
    Lambda(int &i) : i_(i) {}
    template<class V>
    void operator()(V &v)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        /* critical section with v and i_ */
    };
private:
    static std::mutex mutex_;
    int &i_;
};
std::mutex Lambda::mutex_;

int i = 0;
Lambda lambda(i);

This would work (with caveats like the private reference i_), but it looks very cumbersome compared to the initial lambda expression. Would there be anything more straightforward?

like image 785
Come Raczy Avatar asked Apr 13 '16 22:04

Come Raczy


People also ask

Is lambda a static function?

A lambda or anonymous method may have a static modifier. The static modifier indicates that the lambda or anonymous method is a static anonymous function. A static anonymous function cannot capture state from the enclosing scope.

What does [=] mean in lambda function?

The [=] you're referring to is part of the capture list for the lambda expression. This tells C++ that the code inside the lambda expression is initialized so that the lambda gets a copy of all the local variables it uses when it's created.

What is the type of a lambda function?

A lambda function is a stateless instantatiation of a function interface because the lambda expression syntax does not allow for the declaration of instance variables (fields). Therefore, there is no statically-defined data and no other methods to be accessed, negating the need for a self-reference.

How do lambda functions work in C++?

A lambda can introduce new variables in its body (in C++14), and it can also access, or capture, variables from the surrounding scope. A lambda begins with the capture clause. It specifies which variables are captured, and whether the capture is by value or by reference.


1 Answers

You can init-capture a shared_ptr, which will be similar to having it defined as a member variable of the closure type, and so all copies of the closure object will share the same mutex:

  auto lambda = [&i, m = std::make_shared<std::mutex>()](auto &v)
  {
      std::lock_guard<std::mutex> lock(*m);
      /* critical section with v and i */
  };
like image 186
Jonathan Wakely Avatar answered Sep 21 '22 22:09

Jonathan Wakely