我需要一種方法來防止symfony 1.4上的進程多次運行。symfony 1.4中的鎖進程
類似於:當用戶正在運行此進程時,試圖運行此進程的其他用戶將收到警告消息,通知進程正在運行。
有沒有一種方法來實現它,而不使用數據庫?
我需要一種方法來防止symfony 1.4上的進程多次運行。symfony 1.4中的鎖進程
類似於:當用戶正在運行此進程時,試圖運行此進程的其他用戶將收到警告消息,通知進程正在運行。
有沒有一種方法來實現它,而不使用數據庫?
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
}
你的代碼工作就像一個奇蹟。 –
你可以舉例'觸摸'可以創造競爭條件? – kirugan
想象一下:你有兩個請求同時進來,並且都調用lock()。請求A執行if語句。 $文件不存在,所以它不會死。但它尚未執行「觸摸」線。現在請求B執行if語句。 $文件還不存在,所以它也不會死。現在這兩個請求都認爲他們有鎖。在我的代碼中,flock()保證是原子的(它一次發生並且不能被操作系統中斷),所以即使兩個進程一個接一個地執行那條線,只有一個會得到鎖,另一個會得到FALSE。 –
這裏是我的功能是:
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
功能。您可以使用相同的方法將此片段保存爲類,或者將其另存爲助手文件
你可以寫一個'.lock'文件,例如,檢查該文件在運行過程中存在的時。當前用戶停止進程時,不要忘記刪除'.lock'文件。 – j0k
我已經考慮過這個解決方案。但如果用戶丟失連接或服務器出現問題,則不會刪除文件 –
但是,如果不使用數據庫,將很難。使用時,您可以知道用戶是否空閒(例如使用sfPdoSessionStorage),因爲時間過長,然後重置'.lock'文件。 – j0k