Calling Go Functions from Lisp – Part 2

Written by on June 24, 2018 in Golang, LISP, Programming with 0 Comments

In my earlier article Calling Go Functions from Lisp, I explained the steps for making calls to Go functions from another language, specifically LispWorks Lisp. Today, I want to give a slightly more  interesting example showing the use of Go channels through exported functions.

Go is widely admired for its native support for concurrency via Goroutines. Synchronization without explcit locks or condition variables is facilitated by Channels. This greatly simplifies concurrent programming. So, why can’t we take advantage of this powerful feature of Go and use it in another language environment? I am not saying that this alone is sufficient reason for integrating Go runtime with another language program, but it is an appealing reason!

Anyway, without getting into a debate on this topic, let me show you how easy it is to do this.

The following figure shows three Go functions that I have defined for working with a Go Channel. 

Go Functions

Go Functions

For simplicity, I am using a single channel of type int. The function createChannel is used to initialize this global channel. The function writeToChannel writes an integer value to the channel and the third function readFromChannel reads an integer from the channel. All three functions are exported.

The next step is to create a LIB file and Header file from the Go source.

> go build -o GoFunctions.lib -buildmode=c-shared GoFunctions.go

As discussed in the article, we need to write appropriate C wrapper functions that get compiled into a DLL. See the following figure.

Wrapper Functions

Wrapper Functions

Building the DLL is a two-step process:

> gcc -c GoFunctionsWrapper.c

> gcc -shared -o GoFunctionsWrapper.dll GoFunctionsWrapper.o GoFunctions.lib

We have to copy GoFunctionsWrapper.dll and GoFunctions.lib to our Lisp project directory (or make sure they are in executable path).

Lisp Layer:

Now we are ready to write our LispWorks Lisp code. As discussed in the earlier article, we have to declare the DLL functions in Lisp and ensure that the DLL is registered properly.

Declaring the DLL Functions

Declaring the DLL Functions

Now comes the interesting part. Since channels are meaningful only in concurrent programs, in order to use and test them, we have to write a multi-threaded Lisp program. Here is the simplest one that uses the Go functions we have implemented:

Multi-threaded Access

Multi-threaded Access

I am writing to the channel in a separate thread (similar to goroutines), while reading from the same channel in the main thread.

Here is the output when I run the function:

Testing Channel

Testing Channel

Super. What will happen if we write to the channel (unbuffered) and read from it in the same thread? Deadlock, right? Here is the version I wrote to test that behavior:

Deadlock Version

Deadlock Version

And here is output:

Testing Deadlock

Testing Deadlock

As expected, the program is deadlocked because after the first element is written, it cannot be consumed by another thread!

So there we are. This example shows that we are able to use Go’s channels via exported functions in a foreign language, in this case Lisp.

As I mentioned in the beginning of this article, before using Go functions in a foreign language, we have to convince ourselves that this has definite advantages. Remember we now have two runtimes in our code, one from Go and another from Lisp. This can cause subtle problems in a large program, so we have to be careful, especially when passing objects around the two different runtimes.

Download the sources from here. Have a great weekend!

Tags: , ,

Subscribe

If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

Your email address will not be published.

Top