1

I am interested to know more about how the std::scoped_lock operates.

I am making some modifications to some thread-unsafe code by adding a mutex around a critical section.

I am using a std::scoped_lock to do this.

There are two possible things which can happen when the line of code std::scoped_lock lock(mutex) is reached:

  1. The mutex is locked successfully. Nothing to be concerned with here.

  2. The mutex is being held by another thread (A). The mutex cannot be locked, and presumably the current thread (B) blocks.

Regarding point 2, what happens when the thread which was able to lock the mutex unlocks it again? ie: When thread A unlocks the mutex (scoped_lock goes out of scope) what does thread B do? Does it automatically wake up and try to lock the mutex again? (Does thread B sleep when it is not able to lock the mutex? Presumably it does not sit in an infinite while(1) like loop hogging the CPU.)

As you can see I don't have a complete understanding of how a scoped_lock works. Is anyone able to enlighten me?

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • As reference, I'd suggest cppreference.com. It may be hard to read, but it contains all info. That said, yes, threads are will continue automatically when the thing causing them to block (mutex, event, IO) is resolved. – Ulrich Eckhardt Nov 01 '21 at 13:26
  • 3
    `std::scope_lock` ultimately just calls `lock()` and `unlock()` on the mutex object. What that means depends on the object it is locking. For `std::mutex` see [`std::mutex::lock`](https://en.cppreference.com/w/cpp/thread/mutex/lock). – François Andrieux Nov 01 '21 at 13:26
  • 1
    All we really know is *If another thread has already locked the mutex, a call to lock will block execution until the lock is acquired.* The how is up to the implementation, so you'd have to check the source code to see how they implement the wait. One approach would be to use a spinlock – NathanOliver Nov 01 '21 at 13:27
  • Thanks for the comments. From this I take it I was correct to assume that it is at least the case that when the thread owning the mutex unlocks said mutex then any threads waiting for the mutex will not be left blocking. (They will unblock - how exactly may be up to the implementation.) – FreelanceConsultant Nov 01 '21 at 13:35
  • IMO, you're looking at it too deeply. @FrançoisAndrieux said that `std::scope_lock` makes a call to `lock()`. OK. `lock()` does _just one thing;_ It acquires the lock. How long that takes depends on whether or not some other thread already owns the lock and, on how many other threads are attempting to acquire it. But, from the point of view of the a thread that's calling `lock()`, you just call it, and when it returns, you own the lock. – Solomon Slow Nov 01 '21 at 13:38
  • _"...Does thread B sleep when it is not able to lock the mutex?..."_ the answer to this is - it depends on the implementation. A common strategy is to hard-loop for a short while and then if the lock is still not free block in the kernel and wait for the kernel to activate the thread. This avoid a kernel switch if the lock is only unavailable for a short time. – Richard Critten Nov 01 '21 at 13:41
  • @SolomonSlow makes sense thanks – FreelanceConsultant Nov 01 '21 at 13:44

1 Answers1

2

Your basic assumptions are pretty much correct - block, don't hog the CPU too much (a bit is OK), and let the implementation deal with thread wake-ups.

There's one special case that should be mentioned: when a mutex is used not just to protect a shared resource, but specifically to coordinate between threads A&B, a std::condition_variable can help with the thread synchronization. This does not replace the mutex; in fact you need to lock a mutex in order to wait on a condition variable. Many Operating Systems can benefit from condition variables by waking up the right threads faster.

MSalters
  • 173,980
  • 10
  • 155
  • 350