Tutorial

Overview #

In this tutorial we will write a stupid example in which we calculate the sum of two numbers and print it.

Basic version #

Let’s write a basic version first. It may look like,

#include <stdio.h>

int add(int a, int b) {
  return a + b;
}

int main(void) {
  printf("The sum of 1 and 2 is %d\n", add(1, 2));
  return 0;
}

Ok, now we want to calculate the sum in another process and print it in current process. How can we achieve it?

Async version #

One solution is we do the calculating in another process and then get the result through the channel.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define csp_without_prefix

#include <stdio.h>
#include <libcsp/csp.h>

chan_declare(ss, int, integer);
chan_define(ss, int, integer);

proc void add(int a, int b, chan_t(integer) *chn) {
  chan_push(chn, a + b);
}

int main(void){
  chan_t(integer) *chn = chan_new(integer)(0);
  async(add(1, 2, chn));

  int sum;
  chan_pop(chn, &sum);
  printf("The sum of 1 and 2 is %d\n", sum);

  chan_destroy(chn);
  return 0;
}

There are many new things. Don’t worry, let’s review it line by line.

In the first line, we defined the macro csp_without_prefix. With it we can use the libcsp’s APIs without the prefix csp_.

In lines 6~7, we declared and defined the a single-writer single-reader(that’s what ss means) channel consisting of int elements. We marked this channel with label integer to avoid naming conflicts with other declared channel(e.g. channel declared with chan_declare(ss, int, num)).

In lines 9~11, we defined the calculating function. It has a parameter chn, thus we can get the sum through the channel. The keyword proc is used to tell the compiler not to inline the function. Libcsp relies on the noinline-ed task.

In lines 14, we created a new channel object. And in line 15 we created and started a new process to run the task add(1, 2, chn) by the libcsp API async.

In lines 17~19, the process blocked until it got the result from the channel. Then we printed the result.

In lines 21~22, we released the channel resource and finally finished.

Sync version #

Ok, the async version solution works fine, congratulations. But wait, can we improve it? Let’s review the async version code again, and we found that,

  • We create a new channel object, but we only use it once and then destroy it. The overhead is somewhat heavy.
  • The main process relies on the task process. It will block until the task process finishes and thus it shouldn’t be tried to be scheduled by the libcsp scheduler meanwhile .

libcsp provides mechanism to solve this, it’s sync. Below is the sync version solution.

#define csp_without_prefix

#include <stdio.h>
#include <libcsp/csp.h>

proc void add(int a, int b, int *sum) {
  *sum = a + b;
}

int main(void){
  int sum;
  sync(add(1, 2, &sum));
  printf("The sum of 1 and 2 is %d\n", sum);
  return 0;
}

Compared to the async version, it’s shorter and faster.

Build #

Assume the file is sum.c, we build it with following commands,

cspcli init
gcc -o sum.o -c sum.c -fplugin=libcsp
cspcli analyze
gcc -o sum sum.o /tmp/libcsp/config.c -lcsp -pthread

Go to Building for more detail about the building.