You are previewing Erlang Programming.

Erlang Programming

Cover of Erlang Programming by Simon Thompson... Published by O'Reilly Media, Inc.
  1. Erlang Programming
    1. SPECIAL OFFER: Upgrade this ebook with O’Reilly
    2. Foreword
    3. Preface
      1. Francesco: Why Erlang?
      2. Simon: Why Erlang?
      3. Who Should Read This Book?
      4. How to Read This Book
      5. Conventions Used in This Book
      6. Using Code Examples
      7. Safari® Books Online
      8. How to Contact Us
      9. Acknowledgments
    4. 1. Introduction
      1. Why Should I Use Erlang?
      2. The History of Erlang
      3. Erlang’s Characteristics
      4. Erlang and Multicore
      5. Case Studies
      6. How Should I Use Erlang?
    5. 2. Basic Erlang
      1. Integers
      2. The Erlang Shell
      3. Floats
      4. Atoms
      5. Booleans
      6. Tuples
      7. Lists
      8. Term Comparison
      9. Variables
      10. Complex Data Structures
      11. Pattern Matching
      12. Functions
      13. Modules
      14. Exercises
    6. 3. Sequential Erlang
      1. Conditional Evaluations
      2. Guards
      3. Built-in Functions
      4. Recursion
      5. Runtime Errors
      6. Handling Errors
      7. Library Modules
      8. The Debugger
      9. Exercises
    7. 4. Concurrent Programming
      1. Creating Processes
      2. Message Passing
      3. Receiving Messages
      4. Registered Processes
      5. Timeouts
      6. Benchmarking
      7. Process Skeletons
      8. Tail Recursion and Memory Leaks
      9. A Case Study on Concurrency-Oriented Programming
      10. Race Conditions, Deadlocks, and Process Starvation
      11. The Process Manager
      12. Exercises
    8. 5. Process Design Patterns
      1. Client/Server Models
      2. A Process Pattern Example
      3. Finite State Machines
      4. Event Managers and Handlers
      5. Exercises
    9. 6. Process Error Handling
      1. Process Links and Exit Signals
      2. Robust Systems
      3. Exercises
    10. 7. Records and Macros
      1. Records
      2. Macros
      3. Exercises
    11. 8. Software Upgrade
      1. Upgrading Modules
      2. Behind the Scenes
      3. Upgrading Processes
      4. The .erlang File
      5. Exercise
    12. 9. More Data Types and High-Level Constructs
      1. Functional Programming for Real
      2. Funs and Higher-Order Functions
      3. List Comprehensions
      4. Binaries and Serialization
      5. References
      6. Exercises
    13. 10. ETS and Dets Tables
      1. ETS Tables
      2. Dets Tables
      3. A Mobile Subscriber Database Example
      4. Exercises
    14. 11. Distributed Programming in Erlang
      1. Distributed Systems in Erlang
      2. Distributed Computing in Erlang: The Basics
      3. The epmd Process
      4. Exercises
    15. 12. OTP Behaviors
      1. Introduction to OTP Behaviors
      2. Generic Servers
      3. Supervisors
      4. Applications
      5. Release Handling
      6. Other Behaviors and Further Reading
      7. Exercises
    16. 13. Introducing Mnesia
      1. When to Use Mnesia
      2. Configuring Mnesia
      3. Transactions
      4. Partitioned Networks
      5. Further Reading
      6. Exercises
    17. 14. GUI Programming with wxErlang
      1. wxWidgets
      2. wxErlang: An Erlang Binding for wxWidgets
      3. A First Example: MicroBlog
      4. The MiniBlog Example
      5. Obtaining and Running wxErlang
      6. Exercises
    18. 15. Socket Programming
      1. User Datagram Protocol
      2. Transmission Control Protocol
      3. The inet Module
      4. Further Reading
      5. Exercises
    19. 16. Interfacing Erlang with Other Programming Languages
      1. An Overview of Interworking
      2. Interworking with Java
      3. C Nodes
      4. Erlang from the Unix Shell: erl_call
      5. Port Programs
      6. Library Support for Communication
      7. Linked-in Drivers and the FFI
      8. Exercises
    20. 17. Trace BIFs, the dbg Tracer, and Match Specifications
      1. Introduction
      2. The Trace BIFs
      3. Tracing Calls with the trace_pattern BIF
      4. The dbg Tracer
      5. Match Specifications: The fun Syntax
      6. Match Specifications: The Nuts and Bolts
      7. Further Reading
      8. Exercises
    21. 18. Types and Documentation
      1. Types in Erlang
      2. TypEr: Success Types and Type Inference
      3. Documentation with EDoc
      4. Exercises
    22. 19. EUnit and Test-Driven Development
      1. Test-Driven Development
      2. EUnit
      3. The EUnit Infrastructure
      4. Testing State-Based Systems
      5. Testing Concurrent Programs in Erlang
      6. Exercises
    23. 20. Style and Efficiency
      1. Applications and Modules
      2. Processes and Concurrency
      3. Stylistic Conventions
      4. Coding Strategies
      5. Efficiency
      6. And Finally...
    24. A. Using Erlang
      1. Getting Started with Erlang
      2. Tools for Erlang
      3. Where to Learn More
    25. Index
    26. About the Authors
    27. Colophon
    28. SPECIAL OFFER: Upgrade this ebook with O’Reilly
O'Reilly logo

Message Passing

Processes communicate with each other using message passing. Messages are sent using the Pid ! Message construct, where Pid is a valid process identifier and Message is a value from any Erlang data type (see Figure 4-2).

Message passing

Figure 4-2. Message passing

Each Erlang process has a mailbox in which incoming messages are stored. When a message is sent, it is copied from the sending process into the recipient’s mailbox for retrieval. Messages are stored in the mailbox in the order in which they are delivered. If two messages are sent from one process to another, the messages are guaranteed to be received in the same order in which they are sent. This guarantee is not extended to messages sent from different processes, however, and in this case the ordering is VM-dependent.

Sending a message will never fail; so if you try sending a message to a nonexistent process, it is thrown away without generating an error. Finally, message passing is asynchronous: a sending process will not be suspended after sending a message; it will instead immediately continue executing the next expression in its code.

To test sending messages in the shell, let’s use the self/0 BIF, which returns the pid of the process in which it is evaluated. The Erlang shell is nothing other than an Erlang process in a read-evaluate-print loop, waiting for you to type in an expression. When you terminate an expression followed by a full stop (.) and press Enter, the shell evaluates what you typed in and prints out a result. Since the shell is an Erlang process, there is nothing stopping us from sending messages to it. To retrieve and display all the messages sent to the shell process, and therefore currently held in the process mailbox, you can use the shell command flush/0, which also has the effect of removing (or flushing) those messages from the mailbox:

1> Pid = self().
2> Pid ! hello.
3> flush().
Shell got hello
4> <0.30.0> ! hello.
* 1: syntax error before: '<'
5> Pid2 = pid(0,30,0).
6> Pid2 ! hello2.
7> flush().
Shell got hello2

What is happening in the preceding example? In command 1, the BIF self() returns a pid, which in the shell is bound to the variable Pid and displayed as <0.30.0>. In commands 2 and 3 you see the message being sent to the Pid, and then flushed from the mailbox, using the flush() command in the shell.

You cannot type pids directly in a module or in the shell, as in both cases, they result in a syntax error; this is shown for the shell in command 4. You need either to bind the process identifiers to a variable when BIFs such as self and spawn return them, or generate a pid using the pid/3 shell function, as shown in command 5 and used in command 6. The flush() in command 7 shows that the message indeed went to the shell process.

Pid ! Message is a valid Erlang expression, and as with all valid expressions in Erlang, it has to return a value. The value, in this case, is the message sent. So if, for example, you need to send the same message to many processes, you can write either a sequence of message sends, such as Pid1!Msg,Pid2!Msg,Pid3!Msg, or a single expression, such as Pid3!Pid2!Pid1!Message, which is equivalent to writing Pid3!(Pid2!(Pid1!Message)), where Pid1!Message returns the message to send to Pid2, which in turn returns the message to be sent to Pid3.

As we already said, sending messages to nonexistent processes will always succeed. To test this, let’s make the shell process crash with an illegal operation. Crashing is the same as an abnormal process termination, something that is considered normal in Erlang, in the sense that Erlang provides mechanisms to deal with it. We will cover abnormal process terminations in more detail in the next chapter, so until then, do not get alarmed. Making the shell crash will automatically result in a new shell process—in this example with pid <0.38.0>—being spawned by the runtime system.

With this in mind, we locate the shell pid, make the shell process terminate, and then send a message to it. Based on the semantics of message passing, this will result in the message being thrown away:

7> self().
8> 1/0.
** exception error: bad argument in an arithmetic expression
     in operator  '/'/2
        called as 1 / 0
9> self().
10> pid(0,30,0) ! hello.
11> flush().

The reason that message passing and spawn always succeed, even if the recipient process does not exist or the spawned process crashes on creation, has to do with process dependencies, or rather, their deliberate lack of dependencies. We say that process A depends on process B when the fact of B terminating can prevent A from functioning correctly.

Process dependencies are very important and will often influence your design. In massively concurrent systems, you do not want processes to depend on each other unless explicitly specified, and in such cases, you want to have as few dependencies as possible. To give a concrete example of this, imagine an IM server concurrently handling thousands of messages being exchanged by its users. Each message is handled by a process spawned for that particular function. If, due to a bug, one of these processes terminates, you would lose that particular message. Ensuring a lack of dependency between this process and the processes handling all the other messages guarantees that these messages are safely processed and delivered to their recipients regardless of the bug.

The best content for your career. Discover unlimited learning on demand for around $1/day.