本来ロックなど存在しないErlangの処理系(というか言語仕様)に排他ロックを作ってみるという暴挙。registered nameがuniqueなことを利用して排他ロックを作る。どこの空間までロックを制限できるかも分からないし、どの程度の負荷に耐えられるのかも微妙というか全くの未知数。使い方:
Eshell V5.6.3 (abort with ^G) 1> c(locker). {ok,locker} 2> locker:lock(hoge, a). {ok,lock_aquired,<0.38.0>,<0.31.0>} 3> locker:lock(hoge, a). {ng,already_locked} 4> locker:unlock(hoge, a). {released,{<0.31.0>,a}} 5> locker:lock(hoge, a). {ok,lock_aquired,<0.43.0>,<0.31.0>} 6>
なんで「ようなもの」かというと、ここがatomicなtest&setとかになっててほしいんだけどなっていないという悲しい現実から:
case whereis(LockName) of undefined -> register( LockName, Pid ),
(追記)
global:set_lock/1, global:del_lock/1でも十分。どうみても骨折り損です。本当にありがとうございました。
モジュールのソース全文は以下から。
-module(locker). -author("kuenishi@gmail.com"). % simple advisory exclusive lock. % I wish the sentence 'case whereid ~ of ~ register' were atomic...; -export([lock/2, unlock/2, lock_runner_/3]). lock(LockName, LockMode)-> % RealLockName=list_to_atom( ["lock_"|atom_to_list(LockName)]), Self=self(), spawn_link( fun()-> Pid = self(), case whereis(LockName) of undefined -> register( LockName, Pid ), Self ! {ok, lock_aquired, Pid, Self}, lock_runner_(Self, LockName, LockMode); _OtherPid -> % io:format("other process[~p] already aquired the lock '~p'.~n", [OtherPid, LockName]), Self ! {ng, already_locked} end end ), receive Result-> Result end. unlock(LockName, LockMode)-> case whereis(LockName) of undefined -> {ng, no_lock}; _Pid -> LockName ! {self(), LockName, LockMode}, receive Message -> Message after 1024 -> failed %timeout by 1024ms end end. lock_runner_(LockHolder, LockName, LockMode)-> receive {From, LockName, SomeLockMode}-> LockHolder ! {released, {From, SomeLockMode} }, {ok, released}; _Other -> lock_runner_(LockHolder, LockName, LockMode) end.