Amanieu / parking_lot

Compact and efficient synchronization primitives for Rust. Also provides an API for creating custom synchronization primitives.
Apache License 2.0
2.76k stars 217 forks source link

Mutex hold and wait for other mutex #96

Open Nokel81 opened 6 years ago

Nokel81 commented 6 years ago

Monitors are thread safe structs and they generally have some way of "yielding" to threads trying to get into the struct instance. These are generally done at the function level but don't necessarily. What would be very useful is the ability, while owning a RAII guard for a Mutex or a ReentrantMutex to give a list of the same.

With that list, the current thread would then wait until ONE thread has entered any of the mutexes listed (priority of the order given) and then exited. With guarantees that after that other thread exits this thread is the next to run.

This would panic if a mutex that is currently in this waiting state is in a provided list.

Amanieu commented 6 years ago

I'm afraid that I don't fully understand what you are talking about. Could you give a code example?

Nokel81 commented 6 years ago

Sorry, after reading what I said again I can see that I did not do a good job at explaining what I think would be beneficial.

Let us say that we have a critical section of some code (say a struct instance) that has multiple entry points (say methods) that we want to have control over. We want to be able to guarantee that only one thread is in the critical section at a time. However, if this was the only requirement then a single Mutex (or ReentrantMutex) would suffice.

So another desire is the ability to control who can enter the critical section, or in other words. Have a method of sharing the critical section. What I am imagining is something in a similar vein to the rust borrow checker and sharing of variables but at run-time instead (because concurrency). Basically, a two level mutex system that while holding a RAII-guard you can share, for some time, the critical section to other threads who are waiting (or will be arriving) at some of the other entry points.

This is generally done when you run into a condition that needs to be fixed and another function is set up to fix it. An example being a producer/consumer with a fixed buffer and if the buffer is full when a producer in in the critical section it then allows and waits for a consumer to come in an consume something so that it can store in the buffer before moving on. The ability to wait on several different functions just adds to the more flexibility. The order provided is usually also the order of preference.

I know that this isn't a code example but I hope that it helps in trying to understand what I am proposing.

Amanieu commented 6 years ago

Have you looked at the bump and unlocked methods on MutexGuard, they sound somewhat similar to what you are looking for.

If you want a more complete solution, then you should look into using a Condvar along with a Mutex: have the producer wait on the Condvar when the buffer is full (releasing the lock while waiting) and have consumers signal the Condvar after they have filled the buffer.

Nokel81 commented 6 years ago

Thanks, I am going to look into that and get back to you shortly if all the proper functionality with the correct guarantees exists for correctness.

Nokel81 commented 6 years ago

So having looked at those functions I have to say that they are close to what I am thinking of but not quite. Also the Condvar only works well in the producer/consumer case and doesn't really scale correctly.

What I am thinking of is a generic mutex over some enum. And when you try and lock you provide one of the enum types to lock under. Lastly, at any time while holding the mutex you can bump with an list of enums and the first task waiting on the first enum (in the order) is put through.

There would also be a bump_and_wait function which waits until one of the allowed tasks waits. All while guaranteeing no barging. Which is when a task that isn't the one at the front of a waiting queue is able to grab the lock after it is unlocked.