简体   繁体   中英

c++ std::lock_guard scope reach

let's assume I have a function that acquires a lock and executes a fuction passed by argument:

template <typename T>
T acquireLock(std::mutex& _lock, const std::function<T()>& execution) {

  try {
    std::lock_guard<std::mutex> mutex (_lock);

    return execution();

  } catch (std::logic_error& error) {

    std::cerr << "[exception caught]\n\t" << error.what() << std::endl;

  }

  return false;
}

Also, I have a class that needs to acquire said lock for some of it's methods.

class MyThreadSafeClass {

 public:

  bool Init();
  bool StopApi();
  unsigned int GetValue() {

      auto ret = acquireLock<unsigned int>(_lock, [this]() -> unsigned int {

        // does some work that's not thread-safe...
        return value;

      });

      return ret;
  }

 private:

  bool _ready = false;
  std::mutex _lock;

};

My doubt is if whenever I call GetValue() , looking at my acquireLock() method, is the execution() call also affected by the lock scope ?

auto myClass = new MyThreadSafeClass();
myClass->GetValue();

Looking at this , more specifically:

When a lock_guard object is created, it attempts to take ownership of the mutex it is given. When control leaves the scope in which the lock_guard object was created, the lock_guard is destructed and the mutex is released.

It's still unclear to me if what happens inside execution() code is still affected by the lock scope.

According to [stmt.return]/p3 :

  1. The copy-initialization of the result of the call is sequenced before the destruction of temporaries at the end of the full-expression established by the operand of the return statement, which, in turn, is sequenced before the destruction of local variables ([stmt.jump]) of the block enclosing the return statement.

So we get:

  1. The mutex is locked
  2. execution() is called while holding the lock
  3. The lock is released
  4. The evaluated value is returned to the caller (or the catch clause is entered)

In other words yes, it will work as intended.


Unrelated note: std::function isn't very efficient. Templating on the callable type should work better:

template<typename F>
auto doLocked(std::mutex& _lock, F const& f) -> decltype(f()) {
    std::lock_guard<std::mutex> lock(_lock);
    return f();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM