I have already skimmed the topic with two posts:
The next promised post should have been about the same matter, tackled using D.E.Knuth's MMIX, mainly because of the GO and PUSHGO instructions.
Well, GO… In the (long) meantime, I have tried to taste Go, Google's «open source programming language that makes it easy to build simple, reliable, and efficient software».
I like it and it blends well with these articles, because of its “goroutines” and channels.
So, let's see how it would be in a high level language1 like Go, kindly providing us all we need to make things work. It will be easier to follow Tatham's article closer, in particular
parser written with the aid of
Something like this example, where there's a quirk2 and I am not sure it's the proper way3 to solve the problem, but it seems reasonable.
Now there are not two “pieces of code” which pass control from one to another and viceversa: in fact, we have routines (a producer and a consumer, if we speak in terms of their roles) running concurrently and sending/receiving data through a “channel” — the producer reads input and sends each decoded byte to the channel; the consumer reads from (and waits on) the channel. The producer does not send the decoded byte only: it says also when something went wrong or the end of the input stream was reached. The consumer uses this information to stop the get-from-channel loop.
Indeed, a single goroutine is enough and makes it possible to drop the explicit synchronization:
main function won't end until the
parser function exits, and the
parser will exit when the consumer will send an EOF through the channel.
My final attempt is as follows.
With respect to 68k, x86 and MMIX assembly…↩
Since the goroutines need their time to finish their work, in the
mainwe need to wait until they end — otherwise, when we exit the
main, goroutines get killed, and likely it will happen soon before input stream dries. We need some kind of synchronization. I have used
sync.WaitGroup: the counter is incremented by 2 (because we have 2 goroutines) in the
wg.Add(2); then each goroutine calls
wg.Done()when it has finished (this happens when an error occurs or input stream reaches end of file).↩
Intuitively, first I did
wg.Add(1)in each goroutine; but it didn't work, likely since the
wg.Wait()before one of those goroutines stepped on
wg.Add(1). So, the main has to set things properly before.↩
Post a Comment