April - 2008 - issue > Technology
Karthik Ramchandra
Monday, March 31, 2008
Whenever we talk of designing software, we talk of modelling our system so that it mirrors the real world as much as possible. We say that we conceptualise objects or services to make them similar to the real world. The real world is concurrent, and consists of a large number of events many of which happen simultaneously. At an atomic level our bodies are made up of atoms and molecules that are in simultaneous motion. At a macroscopic level the universe is populated with galaxies of stars that are in simultaneous motion.

When we perform a simple action, like driving a car, we are aware of the fact that there may be several hundreds of vehicles within our immediate environment, yet we are able to perform the complex task of driving it and avoiding all these potential hazards and hurdles without even thinking about them.

In the real world sequential activities are rare. As we walk down the street we would be very surprised generally to find only one thing happening; we expect to encounter many simultaneous events. If nature had not endowed us with the ability to simultaneously analyse and predict the outcome of many events we would live in great danger, and tasks like driving a car would be impossible. The fact that we can do things which require processing massive amounts of parallel information suggests that we are equipped with mechanisms that allow us to intuitively understand concurrency without consciously thinking about it.

When it comes to computer programming, things suddenly become inverted. Programming a sequential chain of activities is viewed as the norm and is thought of as being easy, whereas programming collections of concurrent activities is avoided as much as possible, and is generally perceived as difficult. This is due to the poor support which is provided for concurrency in virtually all conventional programming languages. The vast majority of programming languages are essentially sequential; any concurrency in the language is provided by the underlying operating system, and not by the programming language. If we write programs that behave the way the natural objects do in the real world, such programs will have a concurrent structure.

In Concurrency Oriented Programming, the concurrent structure of the program should follow the concurrent structure of the application. It is particularly suited to programming applications which are modelled after or interact with the real world.

It is with this approach in mind that Joe Armstrong submitted his thesis on “Making reliable distributed systems in the presence of software errors” which eventually resulted in the birth of Erlang in 1986 (http://www.sics.se/~joe/thesis/armstrong_thesis_2003.pdf). Armstrong has a PhD in computer science from the Royal Institute of Technology in Stockholm, Sweden, and is an expert in the construction of fault tolerant systems. Armstrong was the chief software architect of the project which produced the Erlang OTP system.

Paradigms of Concurrency
In conventional programming languages, concurrency is handled by using shared memory. For example, if two Java threads need to communicate, they share state. The classic solution to the Dining philosophers’ problem (http://en.wikipedia.org/wiki/ Dining_philosophers_problem) is done through this model. According to this, threads must share common state among each other, and can only access it via some form of locking primitives like semaphores.

The other model is called ‘message passing concurrency’, and in this threads share no state and communicate with each other via asynchronous messaging. Since there is no shared state, there is no question of locking at all. Erlang follows this model. In fact, since Erlang is also functional in nature, there are no side effects. To quote from the Pragmatic Erlang book:

“Functional programming forbids code with side-effects. Side-effects and concurrency don’t mix. You can have either sequential code with side-effects, or side-effect free code and concurrency. You have to choose. There is no middle way.”

Concurrency oriented programming
To summarise, these are the salient features of concurrency oriented programming:
Processes are totally independent, as though they run on different machines. Process semantics: No sharing of data => Copy-everything message passing.Sharing => inefficient (can’t go parallel) + complicated (mutexes, locks, ..).Message passing is “send and pray” (i.e., asynchronous).

Erlang Erlang is a functional programming language which is built with concurrency in mind.
It is a language where concurrency belongs to the programming language and not to the operating system. Erlang makes parallel programming easy by modelling the world as sets of parallel processes that can only interact by exchanging messages. In the Erlang world there are parallel processes, but no locks, and no synchronized methods and possibility of shared memory corruption, since there is no shared memory. Erlang programs can be made from thousands or even millions of extremely lightweight processes which run on a single processor that can run on a multi-core processor or be mapped to a network of processors - all transparent to the program.

Let’s have a look at a few simple examples and get a feel of how it would be to code in Erlang:
Example: Sequential
fac(N) when N > 0 -> N * fac(N-1);
fac(0) -> 1.
> math:fac(25).

Another example (this demonstrates the power of declarative functional programming)
qsort([]) -> [];
qsort([Pivot|Rest]) ->
qsort([ X || X <- Rest, X < Pivot]) ++ [Pivot] ++ qsort([ Y || Y <- Rest, Y > Pivot]).

A parallel example:
loop() ->
{rectangle, Width, Height}
io:format(“Area of the rectangle: ~p~n” ,[Width * Height]),
{circle, R} ->
io:format(“Area of the circle: ~p~n” ,[3.14159 * R * R]),
Other ->
io:format(“Unknown shape ~p~n”, [Other]),
1> Pid = spawn(fun area_server:loop/0).
2> Pid ! {rectangle, 6, 10}.
Area of the rectangle: 60
3> Pid ! {circle, 23}.
Area of the circle: 1661.90
4> Pid ! {triangle,2,4,5}.
Unknown shape {triangle,2,4,5}

In the above example, the function spawn (Function) creates a new parallel process and returns its ‘Pid’. The ‘!’ symbol is called the ‘send operator’ and it sends the message to the process. The message can be any ‘tuple’. The ‘receive...end construct’ receives a message which is sent to this process. After receiving it, the message is pattern-matched with the different options in the block (can be compared to a switch case with pattern matching) and the code following the pattern which was matched gets executed. These are simple examples that give a glimpse of Erlang, but in no way demonstrate the power of Erlang and its features.

The software programmers are now at a stage where hyper-threaded multi-core processors are becoming commonplace. If the programming language is not able to parallelize your program and utilize the power of the hardware, we will end up in a tricky situation for which only the software will have to be blamed. Languages like Erlang can exploit the power of the hardware and can take on the much avoided concurrent programming with great ease. It is time to start exploring this avenue before we are left behind.


Programming Erlang by Joe Armstrong http://pragprog.com/titles/jaerlang

Joe Armstrong's thesis http://www.sics.se/~joe/thesis/armstrong_thesis_2003.pdf
An interesting article about concurrency http://www.defmacro.org/ramblings/concurrency.html
Joe Armstrong's blog http://armstrongonsoftware.blogspot.com/
Download Erlang at: http://www.erlang.org

Share on LinkedIn

Previous Magazine Editions