% (1).编写一个 my_spawn(Mod, Func, Args) 函数。它的行为类似 spawn(Mod, Func, Args),
% 但有一点区别。如果分裂出的进程挂了,就应打印出一个消息,说明进程挂掉的原因以及
% 在此之前存货了多长时间。
-module(myspawn).
-export([my_spawn/3]).
-spec my_spawn(Mod, Func, Args) -> pid() when
Mod :: atom(),
Func :: atom(),
Args :: [T],
T :: term().
my_spawn(Mod, Func, Args) ->
{Hour1, Minute1, Second1} = time(),
Pid = spawn(Mod, Func, Args),
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Why} ->
{Hour2, Minute2, Second2} = time(),
io:format("error:~p, time:~pS~n", [Why, (Hour2-Hour1)*60*60+(Minute2-Minute1)*60+(Second2-Second1)])
end
end),
Pid.
% (2).用本章前面展示的 on_exit 函数来完成上一个练习。
-module(myspawn).
-export([my_spawn/3]).
my_spawn(Mod, Func, Args) ->
{Hour1, Minute1, Second1} = time(),
on_exit(spawn(Mod, Func, Args), fun() -> io:format("error......~n") end),
{Hour2, Minute2, Second2} = time(),
io:format("time:~p~n", [(Hour2-Hour1)*60*60 + (Minute2-Minute1)*60 + (Second2-Second1)]).
on_exit(Pid, Fun) ->
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Why} ->
Fun(Why)
end
end).
% (3).编写一个 my_spawn(Mod, Func, Args, Time) 函数。它的行为类似spawn(Mod, Func, Args),
% 但有一点区别。如果分裂出的进程存活超过了Time秒,就应当被摧毁。
-module(myspawn).
-export([my_spawn/4, start/0, func/1]).
% 类型声明
-spec my_spawn(Mod, Func, Args, Time) -> pid() when
Mod :: atom(),
Func :: atom(),
Args :: [T],
T :: term(),
Time :: term().
% 启动函数
start() ->
my_spawn(myspawn, func, [], 5000).
% 创建一个进程和一个监视进程
my_spawn(Mod, Fun, Args, Time) ->
Pid = spawn(Mod, Fun, [Time]),
io:format("Pid:~p~n", [Pid]),
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Why} ->
io:format("Pid:~p process quit~n", Pid),
io:format("Why Quit:~p~n", [Why])
end
end),
Pid.
% 创建的进程执行函数,当超时Time后,退出并发送一个退出信号给监视进程,监视进程接受后打印该进程的 Pid 和退出的原因 Why。
func(Time) ->
io:format("Time:~p~n", [Time]),
receive
{ok, Message} ->
io:format("Message:~p~n", Message)
after Time ->
exit("timeout")
end.
5秒后打印 =ERROR REPORT===
% (4).编写一个函数,让它创建一个每隔5秒就打印一次“我还在运行”的注册进程。
% 编写一个函数来监视这个进程,如果进程挂了就重启它。启动公共进程和监视进程。
% 然后摧毁公共进程,检查它是否会被监视进程重启。
-module(myspawn).
-export([start/0, my_spawn/3, func/0]).
start() ->
my_spawn(myspawn, func, []).
my_spawn(Mod, Func, Args) ->
Pid = spawn(Mod, Func, Args),
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Why} ->
io:format("接受到消息:~p,正在重启进程~n", [Why]),
spawn(Mod, Func, Args),
io:format("重启完毕...~n"),
monitor(process, Pid)
end
end),
Pid.
func() ->
receive
{ok, Message} ->
exit(Message)
after 5000 ->
io:format("我还在运行~n"),
func()
end.
注意,即使函数不在模块外面使用,也必须
export
导出,否则运行失败。
我这里有两个版本,一个正确,一个错误
版本1 正确运行
% (5).编写一个函数来启动和监视多个进程。
% 如果任何一个工作进程非正常中止,就重启它
-module(myspawn).
-export([my_spawn/4, start/1, for/3, spawn_func/0, list_func/3]).
start(N) ->
my_spawn(myspawn, spawn_func, [], N).
my_spawn(Mod, Func, Args, N) ->
% 创建 N 个进程。
% 创建监视进程
Monitor = spawn(fun() ->
Fs = list_func(N, [], spawn_func),
% spawn_link 注意如果一参版本,只能用`fun()-> ... end`匿名函数作为参数,如果是三参版本,Func参数可以是普通函数
Id = [spawn_link(myspawn, F, []) || F <- Fs],
receive
{'DOWN', _, process, Pid, Why} ->
io:format("Pid:~p quit, Reason:~p~n", [Pid, Why]),
io:format("正在重启进程~n"),
spawn_link(Func),
io:format("重启完毕~n")
end
end),
io:format("Monitor:~p~n", [Monitor]).
spawn_func() ->
io:format("hello world:~p~n", [self()]),
receive
{ok, Message} ->
exit(Message);
other ->
spawn_func()
end.
list_func(N, H, F) when N =/= 1 ->
list_func(N-1, [F|H], F);
list_func(N, H, F) when N =:= 1 ->
H.
版本2
参数错误
% (5).编写一个函数来启动和监视多个进程。
% 如果任何一个工作进程非正常中止,就重启它
-module(myspawn).
-export([my_spawn/4, start/1, for/3, spawn_func/0, list_func/3]).
start(N) ->
my_spawn(myspawn, spawn_func, [], N).
my_spawn(Mod, Func, Args, N) ->
% 创建 N 个进程。
% 创建监视进程
Monitor = spawn(fun() ->
% 为何不能 for 循环创建spawn_link?我猜想可能是在Monitor进程外部调用函数,获得不到Monitor信息,所以不能和Monitor连接起来?问题先放这里,感兴趣小伙伴可以留言一起讨论
for(1, N, spawn_link),
receive
{'DOWN', _, process, Pid, Why} ->
io:format("Pid:~p quit, Reason:~p~n", [Pid, Why]),
io:format("正在重启进程~n"),
spawn_link(Func),
io:format("重启完毕~n")
end
end),
io:format("Monitor:~p~n", [Monitor]).
spawn_func() ->
io:format("hello world:~p~n", [self()]),
receive
{ok, Message} ->
exit(Message);
other ->
spawn_func()
end.
for(Max, Max, Func) -> [Func(myspawn, spawn_func, [])];
for(I, Max, Func) -> [Func(myspawn, spawn_func, []) | for(I+1, Max, Func)].
% (6).编写一个函数来启动和监视多个工作进程,如果任何一个进程非正常终止,
% 就摧毁所有进程,然后重启它们。
-module(myspawn).
-export([my_spawn/4, start/1, spawn_func/0, list_func/3]).
start(N) ->
my_spawn(myspawn, spawn_func, [], N).
my_spawn(_, _, _, N) ->
Monitor = spawn(fun() ->
% 创建 N 个进程
Fs = list_func(N, [], spawn_func),
Id = [spawn_link(myspawn, F, []) || F <- Fs],
io:format("Id:~p~n", [Id]),
receive
{'DOWN', _, process, Pid, normal} ->
Pid;
{'DOWN', _, process, Pid, Why} ->
io:format("Pid:~p quit, Reason:~p~n", [Pid, Why]),
% 杀死所有工作进程
[exit(Cpid, normal) || Cpid <- Id],
io:format("正在重启所有进程~n"),
% 新建所有工作进程
[spawn_link(myspawn, F, []) || F <- Fs],
io:format("重启完毕~n")
end
end),
io:format("Monitor:~p~n", [Monitor]).
spawn_func() ->
io:format("hello world:~p~n", [self()]),
receive
{ok, Message} ->
exit(Message);
other ->
spawn_func()
end.
list_func(N, H, F) when N =/= 1 ->
list_func(N-1, [F|H], F);
list_func(N, H, _) when N =:= 1 ->
H.