[ruby-core:124278] [Ruby Feature#21788] Promote Thread::Monitor to a core class
Issue #21788 has been reported by byroot (Jean Boussier). ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
Issue #21788 has been updated by Eregon (Benoit Daloze). +1 I think `MonitorMixin` and `MonitorMixin::ConditionVariable` are small enough that it would be good to have them in core too. BTW `wait_while`/`wait_until` are good patterns and maybe something `Thread::ConditionVariable`, out-of-topic I know but the point is `MonitorMixin` seems well done and core-worthy. `mon_initialize` could also be made safer potentially if it's made core, e.g. to use an internal lock on the object (or the GVL) or so. ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788#change-115784 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
Issue #21788 has been updated by shugo (Shugo Maeda). I am neutral on whether to make `monitor` built-in partially or fully, but backward compatibility for code that calls `require 'monitor'` should be maintained. Speaking of MonitorMixin, it's just a shorthand form inspired by Java's `synchronized` mechanism, where the object representing the protected resource itself acts as a synchronization primitive. However, MonitorMixin::ConditionVariable is even more critical, as it's essential for coordinating with other threads that need to access the protected resource. In Java's `synchronized` mechanism, the protected object itself also serves as a condition variable. However, this necessitates using broadcast (notifyAll) instead of signal (notify) when waiting on multiple conditions. To address this, `monitor` decouples condition variables into separate objects. ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788#change-116058 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
Issue #21788 has been updated by ko1 (Koichi Sasada).
Monitor is about as useful as Mutex and yet one is a core class and the other is a "stdlib" extension.
Do you mean it is useful because of recursive mutex? If it is the reason, `Mutex.new(recursive: true)` or something similar is another idea. ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788#change-116081 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
Issue #21788 has been updated by byroot (Jean Boussier).
Do you mean it is useful because of recursive mutex?
It's very often used as one. In my case I'm interested in speeding it up, to help speedup synchronized constructs such as connection pools, so I need the condition variable. ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788#change-116090 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
Issue #21788 has been updated by Eregon (Benoit Daloze). ko1 (Koichi Sasada) wrote in #note-5:
Do you mean it is useful because of recursive mutex? If it is the reason, `Mutex.new(recursive: true)` or something similar is another idea.
Mutex is already very well established as "non-recursive/non-reentrant" and Monitor as recursive/reentrant so I think `Mutex.new(recursive: true)` would only add confusion now. I think it's a good idea to make Monitor core, and I mostly agree with the PR at https://github.com/ruby/ruby/pull/15538. Main remaining discussion point for me is https://github.com/ruby/ruby/pull/15538#discussion_r2659721652, i.e. I think all `Monitor` methods should be in core, and `monitor.rb` would only contain `MonitorMixin`. `MonitorMixin::ConditionVariable` is moved to `Monitor::ConditionVariable` which is a good cleanup as that's usable without `MonitorMixin`. ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788#change-116120 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
Issue #21788 has been updated by Eregon (Benoit Daloze). BTW both Mutex and Monitor support ConditionVariable, so I don't think there is an argument that a Monitor is more than just a reentrant Mutex, it's not, it's just that. ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788#change-116121 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
Issue #21788 has been updated by ko1 (Koichi Sasada). BTW, why performance is improved? ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788#change-116353 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
Issue #21788 has been updated by byroot (Jean Boussier).
BTW, why performance is improved?
For the most part is because being in core allow to remove many `GET_EC()` calls. First being in core we can use the `Primitive` API, so we recieve the `ec` as first argument, then being inside `thread_sync.c`, we can directly pass down the `ec` to `rb_mut_trylock` and a few other routines. `GET_EC()` is quite costly as it was made non-inlineable: https://github.com/ruby/ruby/blob/2967f98f305b95e7c910facd2d9b3381bd0296a8/v... ---------------------------------------- Feature #21788: Promote Thread::Monitor to a core class https://bugs.ruby-lang.org/issues/21788#change-116358 * Author: byroot (Jean Boussier) * Status: Open * Target version: 4.1 ---------------------------------------- `Monitor` is about as useful as `Mutex` and yet one is a core class and the other is a "stdlib" extension. I propose to promote `Thread::Monitor` as a core class convenience. ### The rest of `monitor.rb` The `monitor` stdlib also contains `MonitorMixin`, but I think this part can remain in `lib/monitor.rb` (or even be moved to `lib/monitor_mixin.rb`. One more questionable part is `Monitor#new_cond`, as it returns a `::MonitorMixin::ConditionVariable` so it would also need to remain in the stdlib. ### Performance benefit By being a core class, Monitor can also be implemented more efficiently, as it is no longer constrained to the public C API. On my branch, monitor is approximately 15% faster (but there might be some more optimizations to be found). `master`: ``` ruby 4.0.0dev (2025-12-17T07:16:32Z master 54d3945ee5) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.952M i/100ms Monitor 1.775M i/100ms Calculating ------------------------------------- Mutex 25.102M (± 0.4%) i/s (39.84 ns/i) - 126.884M in 5.054731s Monitor 21.189M (± 0.1%) i/s (47.19 ns/i) - 106.485M in 5.025493s ``` core monitor: ``` ruby 4.0.0dev (2025-12-17T07:21:34Z core-monitor 32815a1bc4) +YJIT +PRISM [arm64-darwin25] Warming up -------------------------------------- Mutex 1.975M i/100ms Monitor 1.936M i/100ms Calculating ------------------------------------- Mutex 25.213M (± 0.4%) i/s (39.66 ns/i) - 126.407M in 5.013728s Monitor 24.099M (± 0.1%) i/s (41.50 ns/i) - 121.992M in 5.062092s ``` Proposed implementation: https://github.com/ruby/ruby/pull/15538 -- https://bugs.ruby-lang.org/
participants (4)
-
byroot (Jean Boussier) -
Eregon (Benoit Daloze) -
ko1 (Koichi Sasada) -
shugo (Shugo Maeda)