From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-4.1 required=3.0 tests=AWL,BAYES_00, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,SPF_HELO_NONE,SPF_PASS, UNPARSEABLE_RELAY shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id B060F1F8C6 for ; Tue, 14 Sep 2021 01:40:44 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 6503A120B36; Tue, 14 Sep 2021 10:39:21 +0900 (JST) Received: from o1678948x4.outbound-mail.sendgrid.net (o1678948x4.outbound-mail.sendgrid.net [167.89.48.4]) by neon.ruby-lang.org (Postfix) with ESMTPS id 5ABE4120B32 for ; Tue, 14 Sep 2021 10:39:19 +0900 (JST) Received: by filterdrecv-7bf5c69d5-ckn2p with SMTP id filterdrecv-7bf5c69d5-ckn2p-1-613FFD97-2A 2021-09-14 01:40:39.95133988 +0000 UTC m=+1048819.814591170 Received: from herokuapp.com (unknown) by ismtpd0197p1mdw1.sendgrid.net (SG) with ESMTP id Xwz5uypNTIGJEJvZzHFjYw for ; Tue, 14 Sep 2021 01:40:39.816 +0000 (UTC) Date: Tue, 14 Sep 2021 01:40:39 +0000 (UTC) From: "mame (Yusuke Endoh)" Message-ID: References: Mime-Version: 1.0 X-Redmine-Project: ruby-master X-Redmine-Issue-Tracker: Bug X-Redmine-Issue-Id: 17624 X-Redmine-Issue-Author: dazuma X-Redmine-Issue-Assignee: ko1 X-Redmine-Sender: mame X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-Redmine-MailingListIntegration-Message-Ids: 81410 X-SG-EID: =?us-ascii?Q?YbSlef6ZOa=2FS=2FuqSxXRzl42MttQDxKOujGe43WuBjI7JKMg2OkmRsyzG5za6L9?= =?us-ascii?Q?e1flZkYZ9OViVy5Lc4acvpZt2xwytKWyijFtT7u?= =?us-ascii?Q?Cy8oKkOTsDpE1tkIibvqJS6Daa0gpG0E+2D0zHe?= =?us-ascii?Q?u1I7LYG7wFLBGR9B+=2FiyEkaKXUBMuCKkxnZsres?= =?us-ascii?Q?OVHr8TCDdVHhFtEgWP8hnnfIFcfaPeHO8jfeJQ=2F?= =?us-ascii?Q?KmwY4cbhGR2XHZ8hkPxikbsPbNVOU9YfJHpalVr?= =?us-ascii?Q?9mWKxOl0Ce4oyGLbmt9TA=3D=3D?= To: ruby-core@ruby-lang.org X-Entity-ID: b/2+PoftWZ6GuOu3b0IycA== X-ML-Name: ruby-core X-Mail-Count: 105234 Subject: [ruby-core:105234] [Ruby master Bug#17624] Ractor.receive is not thread-safe X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" Issue #17624 has been updated by mame (Yusuke Endoh). Assignee set to ko1 (Koichi Sasada) ---------------------------------------- Bug #17624: Ractor.receive is not thread-safe https://bugs.ruby-lang.org/issues/17624#change-93642 * Author: dazuma (Daniel Azuma) * Status: Open * Priority: Normal * Assignee: ko1 (Koichi Sasada) * ruby -v: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20] * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN ---------------------------------------- It does not seem to be possible to have multiple blocked `Ractor.receive` calls concurrently in the same Ractor (but different threads). One may succeed but the others will hang indefinitely, even if messages are present in the queue. Example code below. It does the following: 1. Starts a Ractor `r1` that spawns two "listener threads". Each thread calls `Ractor.receive`, which blocks waiting for messages. 2. The main Ractor pauses briefly to ensure that the threads have started, and then sends two messages to the Ractor `r1`, with the expectation that each thread will receive one of them. 3. What actually happens is, the `Ractor.receive` call in *one* of the threads will pick a message and return. However, the `Ractor.receive` call in the other thread remains blocked, even though the second message is in the queue. 4. Ractor `r1`, after a pause to ensure that both messages have been sent, issues another `Ractor.receive` call. This call does not block (because the second message is in the queue), and successfully returns the message. Meanwhile, the second thread's `Ractor.receive` call remains blocked. This demonstrates that the second message has been sent successfully and is receivable, even though the second thread still hasn't returned it. It appears that the second thread's receive call is in a bad state. ``` r1 = Ractor.new do # Start two listener threads t1 = Thread.new do puts "T1 received #{Ractor.receive}" end t2 = Thread.new do puts "T2 received #{Ractor.receive}" end # Pause to ensure that both messages have been sent. # (One of the messages will have been picked up by a # thread, but the other remains in the queue.) sleep(3) # Receive the second message. This will succeed, even # though the second thread is still blocked. puts "Later received #{Ractor.receive}" # Wait for the threads to finish. # This will never complete because one of the threads will not # receive the second message, and is still blocking. [t1, t2].each(&:join) :ok end # Make sure both receive calls are blocking sleep(1) # Send two messages. r1.send(1) r1.send(2) # This never returns because the ractor never completes. puts r1.take ``` This happens both in 3.0.0 release and on 3.1.0 head. ``` % ruby -v ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20] ``` ``` % ruby -v ruby 3.1.0dev (2021-02-09T13:22:37Z master e7a831de8e) [x86_64-darwin20] ``` Notes: * This also happens when using `receive_if`. * I would expect this use case to be common when writing a Ractor that contains multiple thread-safe "workers". (This was in fact the use case I was trying to implement when I encountered this issue.) Thus, if we decide this is working as intended, we should document it, and possibly suggest to users that they write their Ractor to funnel communication through a single dedicated thread. -- https://bugs.ruby-lang.org/