Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Not in the stdlib, but it exists elsewhere, such as folly::Synchronized. There are some gotchas but it's a LOT better than a separate mutex and data. The main gotcha is instead of

  for (auto foo : bar.wlock()) {
      baz(foo);
  }
You need to do

  bar.withWLock([](auto &lockedBar) {
      for (auto foo : lockedBar) {
          baz(foo);
      }
  });
In rust, the lifetime checking prevents that.

The other big gotcha is accidentally blocking while holding a lock. E g. Instead of

  auto g = bar.wlock();
  baz(*g);
  co_await quux();
You should do

  {
      auto g = bar.wlock();
      baz(*g);
  }
  co_await quux();
Or use withWLock. If you co_await with the lock held you can deadlock if the executor switches to a different coroutine that tries to acquire the same lock. If you actually need to hold the lock across the blocking call, you need coroutine-aware locks, which turns it into

  auto g = co_await bar.wlock();
  baz(*g);
  co_await quux();
No idea if rust prevents this problem - I suspect not, but I haven't used async rust.


It is possible to fall asleep in Rust while holding a lock, but it's possible to statically detect this mistake/ infelicitious choice in the software and diagnose it. Clippy calls this await_holding_lock - unfortunately the current Clippy diagnosis sometimes gives false positives, so that needs improving.

Tokio provides a Mutex like your final example that is intended for use in such async code that will hold locks while waiting because Tokio will know you are holding the lock. It is accordingly more expensive, and so should only be used if "Don't hold locks while asleep" was not a practical solution to your problem.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: