2012-11-30 61 views
1

我試圖找到一種簡單的方法來確保通過同一命令的多個實例獨佔訪問資源,同時確保無論哪個進程都需要資源首先會先得到它。first-order-first-served fair mutex

如果我做的:

#! /bin/sh - 
{ flock 3 
    some-possibly lengthy code 
} 3<> some-resource 

flock(1)使用flock(2)),我得到的獨家訪問,但此腳本證實:

flock a-resource sleep 6 & 
for i in 1 2 3 4 5; do 
    sleep 1 
    flock a-resource echo "$i" & 
done 
wait 

,我們已經有了一個進程(sleep )持有資源6秒,在此期間5個其他進程請求訪問資源,在sleep已放棄資源後獲得資源的人是隨機的。

看起來像fcntl(F_SETLK)信號量 API不能保證首先提供的服務。

是否有Linux系統API(儘管我也有興趣知道關於可移植性還是來自其他Unices),這將允許這樣做,而不必在用戶空間中實現它?

如果不是這樣,這將是實現一種機制的過程中,要求對資源的獨佔訪問不需要專用主管過程,仲裁資源的分配和最好的方式,其中流程等待在資源被放棄之前資源將會睡眠(不會被調度),並且這將保證首先被訂購的服務)?

雖然這是一個理論問題,但爲了幫助理解問題,一個真實的例子可能是由某個Web服務器運行的CGI腳本,它基於Web客戶端輸入更新文件的內容,我想確保如果Joe先查詢該URL,如果露西之後詢問它,它將在露西之前得到響應。我想規範的方法是建立一個序列化請求的守護進程。我知道該怎麼做,我只想知道是否有一個Unix API會授予排它鎖,同時將請求的進程放入以FIFO方式處理的隊列中。或者,如果沒有,一些整潔/巧妙的機制(整潔,更少過度設計/笨重,我可以與,看到我自己的答案)做到這一點。

+0

如果是希望只有一個進程一次訪問控制資源的FIFO,爲什麼您需要資源控制呢?即對於1 2 3中的x;做睡1;睡覺6; echo $ i;完成 – DarkHeart

+0

@DarkHeart,那個例子只是爲了說明的目的。我們假設在一般情況下,我無法控制這些進程何時開始或需要多長時間。我只是希望他們排隊等待資源,沒有人跳過隊列。 –

回答

1

我希望/期待會有一個API,因爲這聽起來並不罕見。但是,這將是一個我可以想到的以FIFO方式獲得排他鎖的機制的例子。

我確定這樣做肯定不會太笨拙,我開始覺得堆棧溢出問題越來越多。

在這個解決方案中,我們對隊列中等待的每個進程使用一個鎖。這樣,如果一個進程意外死亡,它的座位會自動回收,我們正在避免死鎖。在資源被使用的同時,所有其他進程都在等待,但一旦它被釋放,就有很多鎖定洗牌。

#! /bin/zsh - 
resource=some-file 

setopt extendedglob 

# Acquire exclusive lock for managing the tail of the queue 
exec 3<> $resource.q; flock 3 

# current queue in reverse order 
seats=($resource.<->(NnOn)) 

# create a new seat for us. 
my_seat=$resource.$((${seats[1]:e}+1)) 

seats=($seats $resource) 

# claim this seat 
curr_seat=$my_seat 
exec 4<> $curr_seat; flock 4 

# release the queue-tail lock 
exec 3>&- 

# Now go up the queue 
for next_seat ($seats) { 
    exec 5<> $next_seat; flock 5 

    # Now we hold two seats. Lock the queue to release our pre 
    exec 3<> $resource.q; flock 3 

    # If there was nobody behind us, remove our previous seat 
    [[ -e $resource.$((${curr_seat:e}+1)) ]] || rm -f "$curr_seat" 
    exec 3>&- 4>&5 
    curr_seat=$next_seat 
} 
exec 5>&- 
# Now curr_seat == resource 

some lengthy process 

# resource unlocked upon exit