Introduction to Erlang (iv)--error handling and robustness

Source: Internet
Author: User
Tags emit exit in

Went to Fuzhou, things did not fix, entrusted to the students to help deal with, home rest two days to work. Home these days the biggest harvest is the fourth time to reread the "deep Java Virtual Machine", previously unclear chapters enlightened, a sense of enlightened feeling, it seems, the technology of learning or anxious not to come.
Gossip does not mention, continue the study of Erlang, last learned the chapter of distributed programming, the remaining three chapters are error handling, construction of robust systems and miscellaneous, error handling and construction of a robust system read together today, only take note.
Any language has its own error handling mechanism, Erlang is no exception, syntax error compiler can help you to point out, and logic errors and run-time errors only by the programmer using Erlang provided by the mechanism to properly handle, put the program crash.
The mechanisms of Erlang are:
1) Monitor the execution of an expression
2) Monitor the behavior of other processes
3) Catch undefined function execution error, etc.

First, catch and throw statements
Calling an expression that produces an error causes an abnormal exit of the calling process, such as an incorrect pattern match (2=3), in which case a catch statement can be used:

Catch expression

Try an example, a function foo:

Foo (1)
Hello
Foo (2)
Throw ({myerror, abc});
Foo (3)
Tuple_to_list (a);
Foo (4)
Exit ({myexit, 222}).


When a catch is not used, assume that a process called the PID is calling function foo (in a module), then:
Foo (1)-Return Hello
Foo (2)-statement throw ({myerror, ABC}) executes because we do not call Foo (2) in a catch, so the process PID terminates because of an error.

Foo (3)-tuple_to_list converts a tuple to a list because a is not a tuple, so the process PID is also terminated due to an error

Foo (4)-because no catch is used, Foo (4) calls the Exit function to terminate the process PID, and the {myexit, 222} parameter is used to describe the reason for the exit.

Foo (5)-the process PID terminates because of a call to Foo (5) because there is no function FOO/1 matching foo (5).

Let's see what it looks like after a catch:

Demo (X)
Case Catch Foo (X) of
{myerror, Args}
{user_error, Args};
{' EXIT ', what}
{caught_error, what};
Other
Other
End.

And then look at the results,
Demo (1)-no error occurred, so the catch statement returns the expression result Hello
Demo (2)-Foo (2) throws an error {myerror, ABC}, returned by catch, so will return {USER_ERROR,ABC}

Demo (3)-foo (3) failed because the parameter is wrong, so catch returns {' EXIT ', Badarg '}, and finally return {Caught_error,badarg}

Demo (4)-return {caught_error,{myexit,222}}
Demo (5)-Return {Caught_error,function_clause}

Catch and throw can be used to wrap code that may produce errors, and throw can be used for tail-recursive exits and so on. Erlang is optimized for tail-recursive optimization with scheme, and none of them have explicit iterative structures (such as for loops)

II. termination of the process
The bifs that calls exit in the process can explicitly terminate the process, and exit (normal) indicates a normal termination, and exit (Reason) gives the reason for an abnormal termination through Reason. The termination of a process is also entirely possible due to a run-time error.

Third, the connected process
The connection between processes is bidirectional, meaning that process a opens a connection to B, which also means a connection from B to a. When the process terminates, an exit signal is sent to all processes connected to it. The format of the signal is as follows:
{' EXIT ', exiting_process_id, Reason}
EXITING_PROCESS_ID refers to the terminated process marker
Reason is the cause of the process termination. If reason is normal, the default behavior of the process that accepts this signal is to ignore the signal. The default processing of the exit signal can be overridden to allow the process to react differently to the acceptance of the exit signal.
1. Connection process:
With link (PID), you can establish a connection between the calling process and the process PID
2. Cancel the connection
Conversely, the connection is canceled by unlink (Pid).
3. Create the process and connect:
Create a process and connect through Spawn_link (Module, Function, argumentlist), which returns the newly created process PID

Through the process of mutual connection, many processes can be organized into a network structure, exit signal (non-normal) emitted from a process (the process terminates), all the processes connected to it and other processes connected to these processes, will receive this signal and terminate, Unless they implement the custom exit signal processing method. Example of a process chain structure:

-module (normal).
-export ([Start/1, P1/1, TEST/1]).
Start (N)
Register (start, Spawn_link (Normal, p1, [N-1])).
P1 (0)
Top1 ();
P1 (N)
Top (Spawn_link (Normal, p1, [N-1]), N).
Top (Next, N)
Receive
X-
Next! X
Io:format ("Process ~w received ~w~n", [n,x]),
Top (Next,n)
End.
TOP1 ()
Receive
Stop-
Io:format ("Last process now exiting ~n", []),
Exit (finished);
X-
Io:format ("Last Process received ~w~n", [X]),
TOP1 ()
End.
Test (Mess)
Start! Mess.


Perform:

> Normal:start (3).
True
> Normal:test (123).
Process 2 received 123
Process 1 received 123
Last process received 123

> Normal:test (Stop).
Process 2 received Stop
Process 1 received Stop
Last process now exiting
Stop


Four, run-time failure
A run-time error will cause the process to terminate abnormally, along with an abnormally terminated exit signal that will be emitted to all connected processes, the exit signal has reason and the reason contains an atom type that describes the cause of the error, common for the following reasons:

Badmatch-match failure, such as a process to 1=3 match, this process will terminate and emit {' EXIT ', from, badmatch} signal to the connected process

Badarg-As the name implies, parameter errors, such as Atom_to_list (123), the number is not atom, so will emit {' EXIT ', from, badarg} signal to the connection process

Case_clause-missing branch matches, such as

M = 3,
Case M of
1-
Yes
2-
No
End.

There is no branch 3, so it will issue {' EXIT ', from, case_clause} to the connection process

If_clause-Similarly, if statements are missing a matching branch

Function_clause-missing matching functions, such as:

Foo (1)
Yes
Foo (2)
No.

If we call Foo (3), because there is no matching function, it will emit {' EXIT ', from, function_clause} to the connected process.

UNDEF-The process executes a nonexistent function

Badarith-illegal arithmetic operations, such as 1+foo.

Timeout_value-illegal timeout setting, must be an integer or infinity

Nocatch-Use throw, no corresponding catch to communicate.

V. Modify the default signal receive action
When the process receives the exit signal, you can modify the default receive behavior by using the Process_flag/2 method. The Execute Process_flag (trap_exit,true) setting captures the exit signal as true to change the default behavior, which is to accept and process the exit signal as a signal for general interprocess communication; Process_flag (Trap_exit,false) The default behavior will be turned back on.
Example:

-module (Link_demo).
-export ([start/0, demo/0, demonstrate_normal/0, DEMONSTRATE_EXIT/1,
demonstrate_error/0, DEMONSTRATE_MESSAGE/1]).
Start ()
Register (demo, Spawn (Link_demo, demo, [])).
Demo ()
Process_flag (Trap_exit, True),
Demo1 ().
Demo1 ()
Receive
{' EXIT ', From, normal}
Io:format ("Demo process received normal exit from ~w~n", [from]),
Demo1 ();
{' EXIT ', From, Reason}
Io:format ("Demo process received exit signal ~w from ~w~n", [Reason, from]),
Demo1 ();
Finished_demo
Io:format ("Demo finished ~n", []);
Other
Io:format ("Demo process message ~w~n", [other]),
Demo1 ()
End.
Demonstrate_normal ()
Link (Demo) (Whereis).
Demonstrate_exit (what)
Link (demo), Whereis
Exit (what).
Demonstrate_message (what)
Demo! What.
Demonstrate_error ()
Link (demo), Whereis
1 = 2.


The created process executes the demo method, and the demo method sets the Trap_exit to true, so the exit signal can be treated like general information in receive, this program is very simple, test to see:

> Link_demo:start ().
True
> Link_demo:demonstrate_normal ().
True
Demo process received normal exit from <0.13.1>
> link_demo:demonstrate_exit (Hello).
Demo process received exit signal Hello from <0.14.1>
* * Exited:hello * *

> Link_demo:demonstrate_exit (Normal).
Demo process received normal exit from <0.13.1>
* * Exited:normal * *

> Link_demo:demonstrate_error ().
!!! Error in Process <0.17.1> in function
!!! Link_demo:demonstrate_error ()
!!! Reason Badmatch
* * Exited:badmatch * *
Demo process received exit signal Badmatch from <0.17.1>


Vi. undefined functions and unregistered names
1. When an undefined function is called, Mod:func (Arg0,..., ArgN), the call is converted to:
Error_handler:undefined_function (Mod, Func, [Arg0,..., ArgN])
The Error_Handler module is the error handling module of the system.

2. When a message is sent to an unregistered process name, the call is converted to:
Error_handler:unregistered_name (Name,pid,message)

3. If you do not use the system's own Error_Handler, you can set your own error handling module via Process_flag (Error_Handler, Mymod).

Vii. Catch Vs. Trapping Exits
The difference between the two is that the application scenario is different, and the trapping exits is applied when the exit signal sent by another process is received, and the catch is used only for expression execution.

The 8th chapter describes how to use error handling mechanism to construct a robust system, using a few examples, I wrote the 8.2 section of the example complete, and add the client process for testing:

-module (Allocator).
-export ([start/1,server/2,allocate/0,free/1,start_client/0,loop/0]).
Start (Resources)
Pid = Spawn (allocator, server, [resources,[]]),
Register (Resource_alloc, Pid).
% function Interface
Allocate ()
Request (Alloc).
Free (Resource)
Request ({Free,resource}).
Request (Request)
Resource_alloc! {self (), Request},
Receive
{Resource_alloc, error}
Exit (Bad_allocation); % exit added here
{Resource_alloc, Reply}
Reply
End.
% the server.
Server (free, allocated)
Process_flag (Trap_exit, True),
Receive
{From,alloc}
Allocate (free, allocated, from);
{From,{free,r}}
Free (free, allocated, from, R);
{' EXIT ', From, _}
Check (free, allocated, from)
End.
Allocate ([r| Free], allocated, from)
Link (from),
Io:format ("Connect client process ~w~n", [from]),
From! {Resource_alloc,{yes,r}},
Server (free, [{r,from}| Allocated]);
Allocate ([], allocated, from)
From! {Resource_alloc,no},
Server ([], allocated).
Free (free, allocated, from, R)
Case Lists:member ({r,from}, allocated) of
True-
From! {Resource_alloc,ok},
Allocated1 = Lists:delete ({R, from}, allocated),
Case Lists:keysearch (from,2,allocated1) of
False->
Unlink (from),
Io:format ("Disconnect ~n from Process ~w", [from]);
_->
True
End
Server ([r| FREE],ALLOCATED1);
False-
From! {Resource_alloc,error},
Server (free, allocated)
End.

Check (free, allocated, from)
Case Lists:keysearch (from, 2, allocated) of
False-
Server (free, allocated);
{value, {R, from}}
Check ([r| Free],
Lists:delete ({R, from}, allocated), from)
End.
Start_client ()
Pid2=spawn (allocator,loop,[]),
Register (client, PID2).
Loop ()
Receive
Allocate->
Allocate (),
Loop ();
{free,resource}->
Free (Resource),
Loop ();
Stop->
True
_->
Loop ()
End.


Go home and have time to elaborate on this example. Perform:

1> C (Allocator).
{Ok,allocator}
2> Allocator:start ([1,2,3,4,5,6]).
True
3> allocator:start_client ().
True
4> client!allocate
.
Allocate connecting client processes <0.37.0>

5> client!allocate.
Allocate connecting client processes <0.37.0>

6> client!allocate.
Allocate connecting client processes <0.37.0>

7> allocator:allocate ().
Connecting client Processes <0.28.0>
{yes,4}
8> client! {free,1}.
{free,1}
9> client! {free,2}.
{free,2}
10> client!allocate.
Allocate connecting client processes <0.37.0>

11> client!allocate.
Allocate connecting client processes <0.37.0>

12> Client!stop.
Stop
13> allocator:allocate ().
Connecting client Processes <0.28.0>
{yes,3}
14> allocator:allocate ().
Connecting client Processes <0.28.0>
{yes,2}
15> allocator:allocate ().
Connecting client Processes <0.28.0>
{yes,1}
16>



Introduction to Erlang (iv)--error handling and robustness

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.