From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Panicz Maciej Godek Newsgroups: gmane.lisp.guile.user Subject: Re: Passing objects between threads Date: Mon, 12 Sep 2016 21:58:02 +0200 Message-ID: References: <87mvjeb80n.fsf@pobox.com> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1473710956 1670 195.159.176.226 (12 Sep 2016 20:09:16 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 12 Sep 2016 20:09:16 +0000 (UTC) Cc: "guile-user@gnu.org" To: Andy Wingo Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Mon Sep 12 22:09:12 2016 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bjXXO-0007ne-Ec for guile-user@m.gmane.org; Mon, 12 Sep 2016 22:09:06 +0200 Original-Received: from localhost ([::1]:44965 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bjXXM-0001IH-IR for guile-user@m.gmane.org; Mon, 12 Sep 2016 16:09:04 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:36885) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bjXO5-0004eN-MG for guile-user@gnu.org; Mon, 12 Sep 2016 15:59:31 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bjXO1-00018j-GD for guile-user@gnu.org; Mon, 12 Sep 2016 15:59:28 -0400 Original-Received: from mail-wm0-f46.google.com ([74.125.82.46]:37735) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bjXO1-00014y-4e for guile-user@gnu.org; Mon, 12 Sep 2016 15:59:25 -0400 Original-Received: by mail-wm0-f46.google.com with SMTP id c131so76358282wmh.0 for ; Mon, 12 Sep 2016 12:59:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=umKM/YBtRInoICOqIzgAy4ZD3sqt+b4R1r1/CsMXGDY=; b=Pb2rn9Y81wwOGXIO/li26MFlXqsVUIyKoFTcO3dozKukFPLBeokPzsLrjF/hIgrU2R Nb7oqb7g08FnIuAp+6H89gZNTMCcmSkK2bMraeJ47jydBsl1prhPYbPYIz9b78d1oljI KPrSRSUe3zJdtpeOBtkDcuI/poArQrOOjzf0r4onQtruzgX27czjk1mYALgmYeeDkasC RyTFt7VLwPQeKKSrFt51ZTX2Q+Qq81o+FpUl2iCt/HQa/cKnpKGNh1yUzqJQD8KQWd2+ jAGAQ/ce8E8ASGchRQMvhgzeuUwyTNJ98PA7X7tN2EbDmC89vswal+WSVCQi6vmyo7Jz ffLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=umKM/YBtRInoICOqIzgAy4ZD3sqt+b4R1r1/CsMXGDY=; b=V2Ycr3fXTpP/ftKNpdiun7W7M9DfTrJPnMLLQHZSA2uU8EApDu/B/XTQQB24QSUnHB 7FH3ELgFMVlaM3K5WS3uCOjwnGwIx59ZNgp54inSb2CmiZRjY8WDOFVadyH+LCtXhIil eO10pxmSo3OQi+zdhYoaivDft2ZHfXDS+mlo7pD7jRKf97Cj6On/WAeO7iaHxa2tp7iA qrVloeQprFCDV1OZFXklHLxdf8Bzag8Xpea1+ch8pwkAbXMXeRYMyLafaz+YHCXqgayz VGuFolSYEoBDNAcSu6mgAbA2Io66CFJtZfqMtBMTO3sWCRXXe+W8S1roDHRgODojegM2 K34g== X-Gm-Message-State: AE9vXwNneg0OHn0OfB6jhlJh3Uzf1KaxcXv2g+lGANtA5S9RKjxaVqPzodzaYsR/4TNG/d+JL6znFmuVYFIkbw== X-Received: by 10.194.29.7 with SMTP id f7mr15805303wjh.99.1473710282955; Mon, 12 Sep 2016 12:58:02 -0700 (PDT) Original-Received: by 10.80.165.46 with HTTP; Mon, 12 Sep 2016 12:58:02 -0700 (PDT) In-Reply-To: <87mvjeb80n.fsf@pobox.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 74.125.82.46 X-Content-Filtered-By: Mailman/MimeDel 2.1.21 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: "guile-user" Xref: news.gmane.org gmane.lisp.guile.user:12904 Archived-At: 2016-09-11 20:34 GMT+02:00 Andy Wingo : > On Sat 10 Sep 2016 11:37, Panicz Maciej Godek > writes: > > > is there any easy way to create a channel (queue) that could be used to > > communicate between threads? In particular, if the queue is empty, I > would > > like the consumer to wait until something appears in it (pretty much li= ke > > the channels in Clojure) > > If you are using kernel threads, you can use something like: > > https://lists.gnu.org/archive/html/guile-devel/2012-02/msg00033.html > > If you are using a user-space library for lightweight concurrency like > 8sync or something, they usually have a channel abstraction. There is > one in https://github.com/wingo/fibers, for example (and in that one, > the channels are themselves threadsafe and can be used for passing data > between fibers running on different kernel threads). A new release is > coming later this evening but it requires the latest development Guile. > > Hah, both look rather complicated. I eventually followed Chris' advice an= d developed "my own" queues, which turned out to be a bit simplified variant of his code: (use-modules (ice-9 nice-9) (ice-9 q) (ice-9 threads)) (define (make-channel) `(,(make-q) ,(make-mutex) ,(make-condition-variable))) (define (channel? c) (and-let* (((queue mutex guard) c) ((q? queue)) ((mutex? mutex)) ((condition-variable? guard))))) (define (send! data #;through channel) (let (((queue mutex guard) channel)) (with-mutex mutex (enq! queue data) (signal-condition-variable guard)))) (define (receive! #;from channel) (let (((queue mutex guard) channel)) (with-mutex mutex (while (q-empty? queue) (wait-condition-variable guard mutex)) (deq! queue)))) > I think more generally, now is a time for a lot of experimentation in > the concurrency side of Guile; I look forward to seeing what people > settle on :) I came up with an interface for thread communication, but I don't know how to implement it -- maybe you (or someone else) would be able to help, or at least warn not to go that way. I am trying to extend my SLAYER framework to support reactive programming. I came up with the following architecture: the event system gathers events and puts them into a queue, for example, pressing key k causes a '(key-down k) event to appear. (define EVENT-QUEUE (make-channel)) (set-event-handler! (lambda (event) (send! event #;through channel))) Then there is this update function, which takes the current state of the world, and an event, and returns an updated event. Thus, the evolution of the world can be understood as the fold-left on the event queue: (define (channel-fold update state channel) (let ((message (receive! #;from channel))) (channel-fold update (update state message) channel))) However, if I put things that way, I have no access to the current state, because it is only a transient variable being passed to the tail-recursive call. I could of course communicate between the threads using a global variable and assignment, but this is nasty. Instead I thought of the following interface: I would like to have two functions, let's call them "exposed" and "snapshot". The first one would behave like identity (or values), except that its evaluation would cause the snapshot value of the current thread to be set. The second function would be used to retrieve the snapshot value, so that it could be accessed from other threads. For example, I could define the evolution thread in the following way: (define evolution (call-with-new-thread (=CE=BB () (channel-fold (=CE=BB (state action) (let ((state* (update state #;with action))) (exposed state*))) initial-state EVENT-QUEUE)))) Then, I could access the state variable using the snapshot procedure, so that -- for example -- I could use it in the drawing routine: (set-display-procedure! (=CE=BB () (draw! (visualization (snapshot evolution))))) What I would like about that solution is that even if the world was updated much faster than the drawing routine could handle, the system could remain responsive. (I also think that this interface would be nice with time-constrained optimization algorithms, so that they could make the best known solution available at any time) However, the problem is that -- while procedures have their properties -- there seems to be nothing similar in the realm of threads. Normally in similar cases I could use a thread-indexed hash table, but in the context of multi-threading it would probably need to be protected by a mutex, and it would likely slow things down. Any suggestions? Also, if the data is immutable, and only one thread does assignments, is it OK to assume that variable reference and assignment are atomic operations, or do I need mutices anyway?