2012-10-17 92 views
0

我需要一種方法來防止symfony 1.4上的進程多次運行。symfony 1.4中的鎖進程

類似於:當用戶正在運行此進程時,試圖運行此進程的其他用戶將收到警告消息,通知進程正在運行。

有沒有一種方法來實現它,而不使用數據庫?

+2

你可以寫一個'.lock'文件,例如,檢查該文件在運行過程中存在的時。當前用戶停止進程時,不要忘記刪除'.lock'文件。 – j0k

+0

我已經考慮過這個解決方案。但如果用戶丟失連接或服務器出現問題,則不會刪除文件 –

+0

但是,如果不使用數據庫,將很難。使用時,您可以知道用戶是否空閒(例如使用sfPdoSessionStorage),因爲時間過長,然後重置'.lock'文件。 – j0k

回答

3

kirugan的方法可能在大多數情況下都適用,但它很容易受到競爭條件的影響,並可能在碰撞事件中卡住。

下面是一個更強大的解決方案。它使用PHP的文件鎖定,所以你知道鎖是原子,如果你忘記稍後釋放鎖或你的進程崩潰,它會自動釋放。默認情況下,獲取鎖是非阻塞的(即,如果該鎖已被另一個進程持有,則getLock()將立即返回FALSE)。但是,如果您願意,您可以擁有呼叫阻止(即等到鎖可用)。最後,您可以爲代碼的不同部分使用不同的鎖。只需使用不同的名稱作爲鎖。

唯一的要求是getLockDir()返回的目錄必須是服務器可寫的。隨意更改鎖定目錄的位置。注意:我認爲flock()在Windows(我使用linux)上可能會有不同的表現,所以仔細檢查一下,如果它對你來說是一個問題。

myLock.class.php

class myLock 
{ 
    /** 
    * Creates a lockfile and acquires an exclusive lock on it. 
    * 
    * @param string $filename The name of the lockfile. 
    * @param boolean $blocking Block until lock becomes available (default: don't block, just fail) 
    * @return mixed Returns the lockfile, or FALSE if a lock could not be acquired. 
    */ 
    public static function getLock($name, $blocking = false) 
    { 
    $filename = static::getLockDir() . '/' . $name; 
    if (!preg_match('/\.lo?ck$/', $filename)) 
    { 
     $filename .= '.lck'; 
    } 
    if (!file_exists($filename)) 
    { 
     file_put_contents($filename, ''); 
     chmod($filename, 0777); // if the file cant be opened for writing later, getting the lock will fail 
    } 
    $lockFile = fopen($filename, 'w+'); 
    if (!flock($lockFile, $blocking ? LOCK_EX : LOCK_EX|LOCK_NB)) 
    { 
     fclose($lockFile); 
     return false; 
    } 
    return $lockFile; 
    } 

    /** 
    * Free a lock. 
    * 
    * @param resource $lockFile 
    */ 
    public static function freeLock($lockFile) 
    { 
    if ($lockFile) 
    { 
     flock($lockFile, LOCK_UN); 
     fclose($lockFile); 
    } 
    } 

    public static function getLockDir() 
    { 
    return sfConfig::get('sf_root_dir') . '/data/lock'; 
    } 
} 

如何使用

$lockFile = myLock::getLock('lock-name'); 
if ($lockFile) { 

    // you have a lock here, do whatever you want 

    myLock::freeLock($lockFile); 
} 
else { 
    // you could not get the lock. show a message or throw an exception or whatever 
} 
+0

你的代碼工作就像一個奇蹟。 –

+0

你可以舉例'觸摸'可以創造競爭條件? – kirugan

+0

想象一下:你有兩個請求同時進來,並且都調用lock()。請求A執行if語句。 $文件不存在,所以它不會死。但它尚未執行「觸摸」線。現在請求B執行if語句。 $文件還不存在,所以它也不會死。現在這兩個請求都認爲他們有鎖。在我的代碼中,flock()保證是原子的(它一次發生並且不能被操作系統中斷),所以即使兩個進程一個接一個地執行那條線,只有一個會得到鎖,另一個會得到FALSE。 –

1

這裏是我的功能是:

function lock(){ 
    $file = __DIR__ . '/file.lock'; 
    if(file_exists($file)){ 
     /* exit or whatever you want */ 
     die('ALREADY LOCKED'); 
    } 
    touch($file); 
} 
function unlock(){ 
    $file = __DIR__ . '/parser.lock'; 
    if(file_exists($file)){ 
     unlink($file); 
    }else{ 
     echoln("unlock function: LOCK FILE NOT FOUND"); 
    } 
} 

function exitHandler(){ 
    echoln('exitHandler function: called');  
     unlock(); 
} 

使用lock功能開始,並在register_shutdown_function()設置exitHandler功能。您可以使用相同的方法將此片段保存爲類,或者將其另存爲助手文件