This manual serves as a programmer's guide for developers who wish make use of multithreading in brainfuck. This is not a beginner's guide to brainfuck. Many excellent brainfuck manuals and tutorials are available on the Internet. The reader is expected to familiarise him- or herself with the original, clean brainfuck language before delving into the extensions presented in this material.

Overview of the Changes

Traditionally, brainfuck programs have worked in the form of a single process. For programs that make no use of the process extensions this still remains the case.

The BFPX runtime builds on this concept by allowing the programmer to create brainfuck processes explicitly. Each process acts as a complete, self-contained, traditional brainfuck program. It has its own, private memory space and memory pointer. Pointer positions, memory contents and programs are not shared across processes once they are created. The figure below shows a BFPX program that has been running for a while. It has three processes.

The presence of multiple processes introduces the need for interprocess communication (IPC) and process synchronisation. To solve these issues, BFPX uses Occam's channel model. Channels offer both a way of passing information between threads and a means to guarantee order in process orchestration.

IPC and program in- and output are both done through channels. This sparked what is probably the biggest change of the runtime. It is no longer possible to read or write information using arbitrary cells of memory. Instead, the standard input, output and error streams can only be accessed from specific memory cells.


There are two cases where processes are created; program start-up and through forking.

At program start-up the mother process is started. This process allocates a piece of memory (typically 32 kilobytes) and sets a pointer to the first element. This is no different from process creation in a regular brainfuck program. Such a program is shown below, in its initial state.

Processes may also be created explicitly by the programmer. This is called forking. Like the fork(2) system call in UNIX, brainfuck processes that fork clone their working memory, so that both the parent and the child process have the exact same state at the time just after the fork. Both the memory image and the current position of the memory pointer are copied. The figure below shows two processes just after a fork. Notice how they are identical.

Unlike forking in UNIX, the parent and child process each have their own code. Forking in BFPX is best viewed as a fork(2) in UNIX where the child executes an exec(3) system call. Both processes proceed to run their piece of the program code after the fork.

All processes have the same rights and responsibilities for the runtime system. They are only different in how the process memory is initialised and what code they execute. Once that is done, there is no distinction in how they are treated or scheduled.

The program code for a child process is enclosed in curly braces, as shown in the figure below. Upon reaching a curly brace, the currently running process forks, cloning its memory and pointer. The parent process then jumps ahead to the instruction after the matching closing brace and continues from there. The child process executes the code between the curly braces.

By convention, we will refer to the first process that is started when the program is run as the mother process. Classic brainfuck programs only have a mother process and no others. When discussing forking a new process, the thread that is being cloned is referred to as the parent process. The new process is a child process. Obviously, child processes can be parents of child processes of their own.

Program Termination

A brainfuck program terminates when the mother processes and all of its descendants have terminated.

Processes terminate when they run out of program code to execute.

Channel Communication

BFPX uses a rendez-vous communication mechanism for both IPC and process synchronisation. In order to exchange data, two processes meet on a the same spot and transfer data from one to the other. The process that first arrives at the meeting point, patiently waits for the second process to arrive.

In BFPX, the memory point is used for the rendez-vous point. Two processes that want to exchange information set their memory pointer to point to the same cell index. Then, one process issues the comma operator to read a byte and the other process issues a dot operator to write a byte. The contents of the referenced cell in the writing process is transferred to the same cell in the reading process. Both processes then continue running as normal.

BFPX channels are best visualised as pipes that run under the process memories, connecting all cells that have the same index. This is shown in the figure below in the form of grey lines that connect the cells.

From this figure, it is clear that there is no way for diagonal communication, i.e. communication where data is exchanged between cells of different indexes.

The process that arrives first blocks until a peer arrives to communicate with. This has the effect of synchronising the two processes. The process that first arrives cannot proceed until its peer has finished its own processing and is ready for exchange data.

If more than one process arrives at a channel with the same operation, all of them block until a peer arrives. So if multiple processes issue a read request on a channel, all of them block until a writer arrives. Which of the waiting processes is served first is undefined.

Input and Output

Most programs need to communicate not only internally, but also exchange information with the outside world. In traditional brainfuck programs, the comma and dot operators were used for this communication. As we know now, BFPX uses these operators for channel communication.

There are three daemon processes in the BFPX runtime. These form the bridge between the outside world and the program. They are the input, the output and the error daemons .The input daemon reads from the standard input stream of the program. It writes all input it receives into the channel that is linked to the cells with index 0. If a process wishes to read information from the keyboard, it can do so by placing its memory cell pointer at index 0 an issuing the comma operator.

The output and error daemons listen on channels 1 and 2 respectively. They write all data they receive over that channel to the standard output and standard error streams, as appropriate.

Using cells 0, 1 and 2 for anything other than communicating with the I/O daemons processes results in undefined behaviour.

Dumping the Core

BFPX supports the hash operator (#) to dump the memory of the process that issues the operator. It dumps the first 10 bytes of memory from that process.

Known Bugs

One known bug in the BFPX compiler is that it does not treat all unknown characters as whitespace. This means that BFPX programs cannot have comments at this time.

photo: Marco Michelini
if you find this interesting, terrible or just would like to know more, e-mail
web statistics