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

After sketching this out, it's nice that this:

    auto x = state.with([](auto& state) { return state.x; });
Becomes this:

    auto x = state.locked()->x;
But it also creates this very accessible footgun:

    auto& x = state.locked()->x;
Where it's way too easy to bind a reference to something that should be protected by the lock, but now isn't. So I'm not sure this is a great idea anymore.


At the end of the day, this is C++, there are no compiler tracked lifetimes and it is easy to leak references out of the lambda as well.

At least the synchronized pattern makes it easy to document which state is protected by which mutex.


> But it also creates this very accessible footgun:

Well, you said it yourself in the article though. There's always ways around the locking; C++ doesn't really give you the full ability to guarantee a field is locked when access. You'll need to either trust the users to some extent or use a style guide to disallow the pattern (I'd suggest only allowing use of auto x = state.locked() to avoid lifetime questions around state.locked()->x). You'd need to use compiler annotations to get any better.


Wait why is this a footgun?


Because now you're holding a reference to `x` which is supposed to be protected by a mutex, even after the mutex is unlocked.

With the lambda-only API, it's much harder to make this mistake, since a temporary reference like this will still go out of scope at the end of the lambda expression.


You specifically mentioned that this is a footgun:

> auto& x = state.locked()->x;

But I don't see how the reference here is gonna make a difference unless i am reading the lifetime of the lock here incorrectly. For example, this is perfectly fine right?

```

{

auto& x = state.locked()->x;

}

```

This will only be a problem if you have an outside struct that holds a reference

```

auto &a = "something";

{

auto& x = state.locked()->x;

a = x;

}

```

Which can still happen even if you use a lambda.


Holding the reference to a field that is protected by a mutex implies there is another thread out there that will race with your reference in either reading or writing it.

Even just a read is racy, as there is no “atomic read” of any size value if it is not already wrapped as atomic.




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

Search: