Re: guile fibers - looking for adivce

2020-09-09 Thread Jan Wielkiewicz
Hello,

Dnia 2020-09-07, o godz. 17:25:38
Aleix Conchillo Flaqué  napisał(a):

> Hi Jan,
> 
> To be honest, I've never used GOOPS so things might be a bit more
> complicated there, I don't know. But it sounds like you have two
> options:
> 
> - Create a fiber with the object and pass data from the object using
> channels to other fibers. Then return data to the main fiber (or the
> fiber that has the object) through a channel and update your object.
> - Make the object global and have fibers that update the object. In
> this case you would need to use mutexes.
> 
> Or maybe you find another way?
> 
> > That said, I might be wrong though.
> > >
> > > Hope this helps,
> > >
> > > Aleix
> >
> > Thanks for explanation, this made my thinking much cleaner. I can
> > get back to experimenting now!
> >
> >
> Cool, let us know!
> Aleix

I actually made a working prototype. Basically I created a new
allocation option for GOOPS slots - #:message.
The default allocation type is #:instance, as explained here:
https://www.gnu.org/software/guile/manual/html_node/Slot-Options.html
The #:message allocation type I introduced treats setting a slot like
sending a message and reading the slot like receiving a message.
I used the example from GOOPS manual as inspiration:
https://www.gnu.org/software/guile/manual/html_node/Customizing-Class-Definition.html

Here's the code. It introduces a new metaclass
 to modify the default behavior and
introduces the #:message allocation type.

(define-class  ())

(define-method (compute-get-n-set (class
) s) (define set-channel (make-channel))
  (define get-channel (make-channel))
  (define stored-value '())
  (define initialized? #f)
  (define (value-updater ch)
(spawn-fiber
 (lambda ()
   (let loop ()
 (set! stored-value (get-message ch))
 (loop)
  (case (slot-definition-allocation s)
((#:message)
 (begin
   (list (lambda (o)
   (if initialized?
   (begin
 (spawn-fiber
  (lambda ()
(put-message get-channel stored-value)))
 (get-message get-channel
 (lambda (o v)
   (spawn-fiber
(lambda ()
  (if (not initialized?)
  (begin
(set! initialized? #t)
(value-updater set-channel)))
  (put-message set-channel v)))
(else (next-method

Using this in practice looks something like this:

(define-class  ()
  (number-of-legs #:setter set-number-of-legs
  #:getter get-number-of-legs
  #:allocation #:message)
  (toys #:setter set-toys
#:getter get-toys
#:allocation #:message)
  #:metaclass )

(define (main)
  (run-fibers
   (lambda ()
 (define dog1 (make ))
 (spawn-fiber
  (lambda ()
(set-number-of-legs dog1 4)
(display "number of legs:\n")
(display (get-number-of-legs dog1 4))
(set-toys dog1 (list 'bone 'dead-rat 'something)
   #:drain? #t))

(main)

This solution allows setting and getting values safely over fibers
through messages, eliminating the problem of parallely editing the same
slot of an object (thanks to just one fiber being able to edit the real
value (value-updater)). If I'm not missing something important, this is
a real solution for a real problem.
I've already tested it with my toy program.
If you have any suggestions, feel free to tell me, also feel free to
use my code, if you find it useful.

I could push this a bit further by making the
 allocate all slots by default
as #:message - this way every object would work safely on fibers,
without the boilerplate code.


Thanks for help, everyone. 

Jan Wielkiewicz



Re: guile fibers - looking for adivce

2020-09-07 Thread Jan Wielkiewicz
Hi!

Dnia 2020-09-05, o godz. 18:19:49
Aleix Conchillo Flaqué  napisał(a):

> Hi!
> 
> On Sat, Sep 5, 2020 at 3:48 PM Jan Wielkiewicz <
> tona_kosmicznego_smie...@interia.pl> wrote:
> 
> I believe sharing the same object by the two fibers defeats the
> purpose of message passing, because with the way you are doing it you
> find exactly the problem you are having and the only way to fix this
> is by using mutexes. That is, you are trying to use fibers as you
> would use regular threads sharing a resource. Instead, there should
> probably be a main fiber (that holds the object) and send messages
> (with the data needed from the object) to 2 other fibers (those would
> be your methods A and B).
I see, thank you for explanation. This allowed me to understand the
problem doesn't lie in the way I was trying to implement my messaging
through fibers, but rather in the way I was using GOOPS - my custom
method for initializing slots called next-method after doing everything
what caused some weird problems with allocation.

Are threads and mutexes worth using, if there are fibers already? 
I know I'll have to learn this eventually, to fully master programming,
but I'm not sure if there's a great advantage over fibers.

> 
> I haven't used fibers extensively, but I've used Go quite a bit which
> follows the same pattern of channels and message passing and this is
> how you would do it.
> 
> Also, the fibers manual also suggests this approach:
> https://github.com/wingo/fibers/wiki/Manual#33-mutation
Yeah, I've read the manual like three times already, but Andy is
somethimes writing sentences from outer space, including the GOOPS
manual. This isn't the level of English I'm currently on.
I guess I'll write some self-explaining examples of GOOPS after I fully
understand it.

> That said, I might be wrong though.
> 
> Hope this helps,
> 
> Aleix

Thanks for explanation, this made my thinking much cleaner. I can get
back to experimenting now!


Jan Wielkiewicz



Re: guile fibers - looking for adivce

2020-09-07 Thread Jan Wielkiewicz
Hi!

Dnia 2020-09-06, o godz. 02:42:20
Zelphir Kaltstahl  napisał(a):

> Hi Jan!
>
> Call me uneducated, but I believe, if you are accessing shared memory,
> in this case the shared member vector of the object, you will have to
> resort to things like locking mechanisms. I don't know of any other
> way, except for not using shared memory and keeping one copy per
> fiber or per concurrently running execution unit.
I'll probably go with some locking mechanism then.

> Is there a way you could avoid sharing the object? Perhaps copying it
> for each fiber?
Fortunately, at least for now, one procedure updates the array and the
other only reads it. We'll see how scalable is my idea when the project
grows. 

> If not, then perhaps there is yet another way. A while ago I read some
> article, which had the heading "pull not push" or something. So
> instead of having multiple concurrent execution units trying to
> update the vector, perhaps you could have multiple concurrent
> execution units, which are each responsible for some exclusive part
> of the state of a data structure and working on their own parts of
> the memory of it and update it by retrieving information from the
> system. Perhaps this is clearer, if I link to the article I read:
Sounds interesting, thanks. Maybe I'll find use for this later.

> https://nullprogram.com/blog/2020/04/30/
> 
> This might only work in cases, where the data lends itself to such
> "other way around" of updating state.
> 
> > Thanks in advance
> > Jan Wielkiewicz
> 
> Out of ideas for now.
> 
> Regards,
> Zelphir
> 
> 

Anyway, thanks for ideas.

Jan Wielkiewicz



guile fibers - looking for adivce

2020-09-05 Thread Jan Wielkiewicz
Hello,

I'm still on my way of integrating Guile Fibers and GOOPS, but I
encountered some weird behavior.
Say I have an object with with one slot being a vector and two methods
accessing the vector concurrently/parallelly. The methods
accessing/editing the vector are time consuming and are meant to be ran
frequently. Assuming I would like to run the methods on separate
fibers, how do I make sure the state of the object doesn't
suddenly change during execution of a method? I would like the methods
to be able to edit the state of the object, but in a cooperative manner.

The weird behavior I've encountered is that sometimes when running the
first method (A) and right after starting the second method (B), the
method B tries to access the vector before the method A finishes its
job. What should I do to make accessing the vector cooperatively, yet
to run the time consuming on separate fibers for concurrency?

I was thinking about implementing slots in objects as sending and
receiving messages instead of regular variables, but still there were
some problems with the object state.

Could someone explain me what should I do?


Thanks in advance
Jan Wielkiewicz



Re: No Guile on Windows?

2020-07-24 Thread Jan Wielkiewicz
Hello,

Dnia 2020-07-24, o godz. 16:00:56
Ludovic Courtès  napisał(a):

> However, my understanding is that Windows Subsystem for Linux (WSL)
> has the potential to make all of us happy.

This is fine as far as we're talking about proprietary Windows, but
this isn't good for software freedom generally - there's ReactOS
(https://reactos.org/) - a free Windows clone that is about to reach
beta stage. It is unlikely they're going to implement WSL there and
therefore Guile will be not usable on this platform. This could
potentially stop Guile users on Windows from switching to ReactOS.
If Guile were running natively on Windows, it would only benefit free
software - more Guile users, more people being interested in Guix and
more people switching to free alternatives.

If no current Guile maintainer is interested in porting it to Windows,
we could at least let people know we're looking for someone who does.
It could be a GSoC proposal, Outreachy something, etc.


Jan Wielkiewicz 



Re: GOOPS and fibers - need help understanding what's wrong, bug in fibers/guile?

2020-07-24 Thread Jan Wielkiewicz
Hello,

Dnia 2020-07-22, o godz. 13:28:14
Chris Vine  napisał(a):

> On further reflection I am not sure if it did used to work with
> guile-2.2.  I think it may be a bug in the manual after all.  This
> works OK:
> 
>   (display (run-fibers
> (lambda ()
>   (let ((channel (make-channel)))
> (spawn-fiber
>  (lambda ()
>(sleep 1) ;; do some work
>(put-message channel "hello world")))
> (simple-format #t "~a~%" (get-message channel))
> "finished\n"
> 
This one just worked, I don't know why, even without "display".
Something is buggy it seems.

> The point about:
> 
>   (run-fibers
>(lambda () (spawn-fiber
>(lambda ()
>  (set! v "Set")
>  (display "hey!\n")
> 
> is that spawn-fiber, and so init-thunk, will return straigntaway with
> a new fiber object.
> 
> So I suspect setting #:drain? to #t will resolve your problem.
#:drain solved the problem and I also managed to make my code work.

> It might be worth reporting the bug in the manual as an issue on the
> github repository (assuming the above is correct).
> 
Yes, I'll report it.

Thanks for helping me!

Posting my working code, so someone wanting to mix GOOPS with fibers
will have a working example:

(define-module (blocks block)
  #:use-module (fibers)
  #:use-module (fibers channels)
  #:use-module (oop goops)
  #:use-module (ice-9 match)
  #:use-module (srfi srfi-9) ;; records
  #:export (
connect-peers
send-message
handle-message
main
p1
p2
get-buffer))

(define-class  ()
  (input #:init-form '() #:getter get-input
 #:setter set-input #:init-keyword #:input)
  (output #:init-form '() #:getter get-output
  #:setter set-output #:init-keyword #:output)
  (buffer #:init-value '() #:setter set-buffer #:getter get-buffer))

;; Only connection, no messaging started.
(define-method (connect-peers (p1 ) (p2 ))
  (let ((p1-p2 (make-channel)) ;; p1 to p2
(p2-p1 (make-channel))) ;; p2 to p1
(set-input p1 p2-p1)
(set-output p1 p1-p2)
(set-input p2 p1-p2)
(set-output p2 p2-p1)))

(define-method (send-message (p ) msg)
  (spawn-fiber
   (lambda ()
 (put-message (get-output p) msg

(define-method (handle-message (p ))
  (spawn-fiber
   (lambda ()
 (let loop ()
   (define msg (get-message (get-input p)))
   (match (pk msg)
  ('ping (send-message p 'pong))
  ('pong (send-message p 'ping)))
   (loop)

(define (main)
  (define p1 (make ))
  (define p2 (make ))
  (connect-peers p1 p2)
  (run-fibers
   (lambda ()
 (handle-message p1)
 (handle-message p2)
 (send-message p1 'ping))
   #:drain? #t))

(main)


---

Jan Wielkiewicz



GOOPS and fibers - need help understanding what's wrong, bug in fibers/guile?

2020-07-21 Thread Jan Wielkiewicz
Hello,

I started writing my project in Guile with GOOPS and fibers (I'll
release it once it stops being a shame and starts working!), but I
encountered a problem:

The example from fibers' manual doesn't work:

(lambda ()
 (spawn-fiber (lambda () (display "hey!\n")

It doesn't print "hey" as documented in the manual.
I use guile 3.0.4 and fibers 1.0.0 (from Guix).

I also tried making a simple proof of concept, but it doesn't seem to
do anything. I would like to understand what's wrong with my code or
report a bug, if this is the case. No errors, warnings, syntax errors,
just silence.

My code:

(define-module (blocks block)
  #:use-module (fibers)
  #:use-module (fibers channels)
  #:use-module (oop goops)
  #:use-module (srfi srfi-9) ;; records
  #:export (
connect-peers
send-message
handle-message
start-listening))

(define-class  ()
  (input #:init-form '() #:getter get-input
 #:setter set-input #:init-keyword #:input)
  (output #:init-form '() #:getter get-output
  #:setter set-output #:init-keyword #:output))

;; Only connection, no messaging started.
(define-method (connect-peers (p1 ) (p2 ))
  (let ((p1-p2 (make-channel)) ;; p1 to p2
(p2-p1 (make-channel))) ;; p2 to p1
(set-input p1 p2-p1)
(set-output p1 p1-p2)
(set-input p2 p1-p2)
(set-output p2 p2-p1)))

(define-method (send-message (p ) msg)
  (put-message (get-output p) msg))

(define-method (handle-message (p ))
  (let loop ()
(define msg (get-message (get-input p)))
(match (pk msg)
   ('ping (send-message p 'pong)))
(loop)))

(define-method (start-listening (p1 ) (p2 ))
  (run-fibers
   (lambda ()
 (spawn-fiber
  (lambda ()
(connect-peers p1 p2)
(handle-message p1)
(send-message p1 'ping)
(handle-message p2))

I run this in repl:

(define p1 (make ))
(define p2 (make ))

(start-listening p1 p2)


-

Thanks in advance,
Jan Wielkiewicz



Re: Handling object communication in GOOPS

2020-07-19 Thread Jan Wielkiewicz
Hello,

Dnia 2020-07-19, o godz. 18:22:17
"Dr. Arne Babenhauserheide"  napisał(a):

> 
> Did you have a look at fibers and channels for this?
> 
> https://github.com/wingo/fibers

Looks like exactly what I need, thanks!

> Best wishes,
> Arne


Jan Wielkiewicz



Re: Handling object communication in GOOPS

2020-07-19 Thread Jan Wielkiewicz
Dnia 2020-07-17, o godz. 13:26:31
Zelphir Kaltstahl  napisał(a):

> Hello Jan,
> 
> to me this sounds like you need to implement perhaps 2 things:
> 
> 1. a setter for the , which takes care of updating
> things, when a completely new  is added.
> 
> 2. some kind of observer pattern, where the  registers
> itself as a listener to changes in the . Probably a
> method at the , something like
> `register-change-listener`, which adds the argument it takes to a
> list or a set of listeners. Then you need to take care, that on
> relevant updates all registered listeners are notified of the change.
> 
> Furthermore you can register the  as a listener at the
>  when the  is set using the setter and
> unregister as listener at the previously set  (which is
> now replaced by the new one).

I'm implementing something like this right now. I'm adding a
 object to every object needing to do messaging.
Once a message is received, the  object will run message
handler provided by the parent object.

I'm surprised Guile isn't providing anything like this right now. If my
knowledge is correct, the original idea of OOP was about sending
messages.

> I have not worked with GOOPS yet, so my answer is not GOOPS specific
> and perhaps there are better ways, but I think this is the classic
> approach to the problem.

It seems GOOPS is pretty minimalistic, I couldn't find anything there,
but I didn't yet study the MetaObject Protocol entirely.

> Regards,
> Zelphir


Thanks
Jan Wielkiewicz



Handling object communication in GOOPS

2020-07-16 Thread Jan Wielkiewicz
Hello,

I would like make objects of two different classes communicate, but I'm
not sure how to implement it or if there already exists something for
the purpose.

Say I have two classes:  and .
During initialization of an  object, it creates a slot
containing  object.

I would like to make the  object to know when address in
the address bar is changed, for example (set-address address-bar1
"/home/user").

Any suggestions? Thanks in advance.


Jan Wielkiewicz