Erlang 避免竞争条件
以下代码片段由Francesco Cesarini和Simon Thompson在《Erlang编程》一书的第112页拍摄,作为Erlang中可能存在的竞争条件的说明Erlang 避免竞争条件,erlang,Erlang,以下代码片段由Francesco Cesarini和Simon Thompson在《Erlang编程》一书的第112页拍摄,作为Erlang中可能存在的竞争条件的说明 start() -> case whereis(db_server) of undefined -> Pid = spawn(db_server, init, []), register(db_server, Pid), {ok, Pid}; Pid wh
start() ->
case whereis(db_server) of
undefined ->
Pid = spawn(db_server, init, []),
register(db_server, Pid),
{ok, Pid};
Pid when is_pid(Pid) ->
{error, already_started}
end.
在不逐字复制详细信息的情况下,作者解释说,如果两个进程同时执行start(),那么运行“undefined”部分的进程1可能无法完成,因为进程2导致它被抢占。然后,进程2将运行“未定义”部分以完成。现在,当进程1恢复时,进程2已经注册了db_服务器,导致对register()的its调用抛出运行时错误。我希望你能理解我的意思,因为我不想窃取这本书的文本
我的问题是,当两个进程同时执行start()时,如何对上述精确的功能进行编码以避免潜在的争用情况?您可以使用a来序列化请求。通常,这是通过让派生的进程注册自己的名称来解决的,然后向其父级发回响应,告知其是否成功
start() ->
Pid = spawn(db_server, init, [self()]),
receive {Pid, StartResult} ->
StartResult
end.
init(Parent) ->
try register(db_server, self()) of
true ->
Parent ! {ok, started},
real_init()
catch error:_ ->
Parent ! {error, already_started}
end.
(可能无法编译或工作。未经检查在此处键入。:)
您可以在gen.erl中找到仔细实现的版本。实际上,在实际代码中,您只需使用OTP行为来重用该版本。您希望启动多少台服务器?您最初的问题暗示了一个,而@cthulahops的评论则暗示了两个,一个服务器和一个备份。对于两台服务器,您可以尝试以下操作:
start() ->
case whereis(db_server) of
undefined ->
Spid = spawn(db_server, init, []),
%% In race condition there can be only one that succeeds to register
case catch register(db_server, Spid) of
true -> {ok,Spid}; %We are it
{error,_} -> %Server registered, register as backup
register(db_server_backup, Spid),
{ok,Spid}
end;
_ -> %Server registered, start backup
Bpid = spawn(db_server, init, []),
register(db_server_backup, Bpid),
{ok,Bpid}
end.
不过我还没有运行过。我知道OTP为这些类型的问题提供了可靠的解决方案,但我对非OTP“设计模式”感兴趣。感谢您的回复。我的问题是,我想使用问题中的start/0,而不是您建议的start/1。例如,我想调用start/0两次,一次调用生成db_服务器,一次调用生成db_备份服务器(如果db_服务器已经注册)。谢谢您的回复。我只是让代码比您的代码稍微通用一点。已编辑为仅启动/0。我刚刚发现您实际上希望启动两台服务器,而不是失败。您可以编辑catch块来注册db_backup_服务器,如果调用了三次,请记住处理错误。这似乎是一个尴尬的设计选择,但对我来说,我宁愿明确开始twoMe太!不幸的是,我受到API的限制,它只允许我为主服务器和备份服务器提供start/0。不过,你重新提出的建议在我看来确实不错。当然,在缺乏正式证据的情况下,我无法证实比赛条件不可能发生。非常感谢您的帮助。我想启动两台服务器。我最初使用O'Reilly书中的例子,因为我认为人们更容易理解,从而回答我的问题。我想启动2台服务器(一台主服务器和一台备份服务器)来提供故障切换。我确实有类似于你建议的代码,但也许你的代码更能避免比赛条件。