flock
synopsis
bool flock ( resource $handle , int $operation [, int &$wouldblock ] )
description
parameters
$operation: 락의 타입을 지정
LOCK_SH: shared lock (reader)
LOCK_EX: exclusive lock (writer)
LOCK_UN: lock 해제
LOCK_NB: non-blocking
$wouldblock: lock이 block 되면 TRUE로 assign 됨. 값은 EWOULDBLOCK errno.
return
example
<?php
$fp = fopen("/tmp/lock.txt", "w+");
if (flock($fp, LOCK_EX)) { // do an exclusive lock
fwrite($fp, "Write something here\n");
flock($fp, LOCK_UN); // release the lock
} else {
echo "Couldn't lock the file !";
}
fclose($fp);
?>
$fp = fopen("/tmp/lock.txt", "w+");
if (flock($fp, LOCK_EX)) { // do an exclusive lock
fwrite($fp, "Write something here\n");
flock($fp, LOCK_UN); // release the lock
} else {
echo "Couldn't lock the file !";
}
fclose($fp);
?>
http://php.net/flock 에는 그 외에도 재미있는 방식들이 많다.
non-blocking 모드로 하는 방법
<?php
$file = fopen('file.txt', 'w');
if(flock($file, LOCK_EX | LOCK_NB)){
echo 'Got lock, continue writing to file';
// Code to write to file
}else{
echo 'File is locked by another process, aborting writing';
// Couldn't obtain the lock immediately
}
?>
$file = fopen('file.txt', 'w');
if(flock($file, LOCK_EX | LOCK_NB)){
echo 'Got lock, continue writing to file';
// Code to write to file
}else{
echo 'File is locked by another process, aborting writing';
// Couldn't obtain the lock immediately
}
?>
디렉토리로 lock을 구현하는 방법
<?php
define("EXCLUSIVE_LOCK", 0);
define("SHARED_LOCK", 1);
define("LOCK", 0);
define("UNLOCK", 2);
define("ADD", 1);
define("SUBSTRACT", -1);
function createLock($fileName) {
$lockDir = "$fileName~";
return @mkdir($lockDir);
} // createLock
function removeLock($fileName) {
$lockDir = "$fileName~";
if(is_dir($lockDir)) {
rmdir($lockDir);
} // if
return true;
} // removeLock
function updateLockFile($fileName, $operation) {
$lockDir = "$fileName~";
$sharedLockFile = "$lockDir/shared";
$exclusiveLockDir = "$lockDir/exclusive";
while(!file_exists($sharedLockFile)) {
if(is_dir($exclusiveLockDir)) {
return false;
}
usleep(10000);
} // while
do {
$locked = !(createLock($sharedLockFile));
if($locked) {
usleep(10000);
} // if
} while($locked);
$handle = fopen($sharedLockFile, "r+b");
$lockNumber = ord(fgetc($handle));
if($lockNumber == 1 && $operation == SUBSTRACT) {
fclose($handle);
unlink($sharedLockFile);
removeLock($sharedLockFile);
rmdir($lockDir);
return;
}
fseek($handle, 0);
fwrite($handle, chr($lockNumber + $operation));
fclose($handle);
removeLock($sharedLockFile);
return true;
} // updateLockFile
function lockFile($fileName, $operation) {
$lockDir = "$fileName~";
$exclusiveLockDir = "$lockDir/exclusive";
$sharedLockFile = "$lockDir/shared";
if($operation == UNLOCK) {
if(is_dir($lockDir)) {
if(is_dir($exclusiveLockDir)) {
rmdir($exclusiveLockDir);
rmdir($lockDir);
} else {
updateLockFile($fileName, SUBSTRACT);
} // if
}
return true;
} // if
$locked = !(@mkdir($lockDir));
if($locked) {
if($operation == EXCLUSIVE_LOCK) {
return false;
} else {
return updateLockFile($fileName, ADD);
return true;
} // if
} else {
if($operation == EXCLUSIVE_LOCK) {
mkdir($exclusiveLockDir);
} else {
createLock($sharedLockFile);
touch($sharedLockFile);
$handle = fopen($sharedLockFile, "wb");
fwrite($handle, chr(1));
fclose($handle);
removeLock($sharedLockFile);
} // if
return true;
} // if
} // lockFile
echo lockFile("a.txt", UNLOCK) ? "gelukt" : "mislukt";
?>
define("EXCLUSIVE_LOCK", 0);
define("SHARED_LOCK", 1);
define("LOCK", 0);
define("UNLOCK", 2);
define("ADD", 1);
define("SUBSTRACT", -1);
function createLock($fileName) {
$lockDir = "$fileName~";
return @mkdir($lockDir);
} // createLock
function removeLock($fileName) {
$lockDir = "$fileName~";
if(is_dir($lockDir)) {
rmdir($lockDir);
} // if
return true;
} // removeLock
function updateLockFile($fileName, $operation) {
$lockDir = "$fileName~";
$sharedLockFile = "$lockDir/shared";
$exclusiveLockDir = "$lockDir/exclusive";
while(!file_exists($sharedLockFile)) {
if(is_dir($exclusiveLockDir)) {
return false;
}
usleep(10000);
} // while
do {
$locked = !(createLock($sharedLockFile));
if($locked) {
usleep(10000);
} // if
} while($locked);
$handle = fopen($sharedLockFile, "r+b");
$lockNumber = ord(fgetc($handle));
if($lockNumber == 1 && $operation == SUBSTRACT) {
fclose($handle);
unlink($sharedLockFile);
removeLock($sharedLockFile);
rmdir($lockDir);
return;
}
fseek($handle, 0);
fwrite($handle, chr($lockNumber + $operation));
fclose($handle);
removeLock($sharedLockFile);
return true;
} // updateLockFile
function lockFile($fileName, $operation) {
$lockDir = "$fileName~";
$exclusiveLockDir = "$lockDir/exclusive";
$sharedLockFile = "$lockDir/shared";
if($operation == UNLOCK) {
if(is_dir($lockDir)) {
if(is_dir($exclusiveLockDir)) {
rmdir($exclusiveLockDir);
rmdir($lockDir);
} else {
updateLockFile($fileName, SUBSTRACT);
} // if
}
return true;
} // if
$locked = !(@mkdir($lockDir));
if($locked) {
if($operation == EXCLUSIVE_LOCK) {
return false;
} else {
return updateLockFile($fileName, ADD);
return true;
} // if
} else {
if($operation == EXCLUSIVE_LOCK) {
mkdir($exclusiveLockDir);
} else {
createLock($sharedLockFile);
touch($sharedLockFile);
$handle = fopen($sharedLockFile, "wb");
fwrite($handle, chr(1));
fclose($handle);
removeLock($sharedLockFile);
} // if
return true;
} // if
} // lockFile
echo lockFile("a.txt", UNLOCK) ? "gelukt" : "mislukt";
?>
fopen($fp, "w+")로 하면 일단 파일을 다 날리고 시작하기 때문에 락을 거는데 실패하면 엿되므로
fopen($fp, "a") 로 하고 락이 성공하면 그때 ftruncate($fp, 0) 으로 날리고 시작하라는 조언도 있고...
<?php
$fp = fopen('yourfile.txt', 'a') ;
if (flock($fp, LOCK_EX)) {
ftruncate($fp, 0) ; // <-- this will erase the contents such as 'w+'
fputs($fp, 'test string') ;
flock($fp, LOCK_UN) ;
}
fclose($fp) ;
?>
$fp = fopen('yourfile.txt', 'a') ;
if (flock($fp, LOCK_EX)) {
ftruncate($fp, 0) ; // <-- this will erase the contents such as 'w+'
fputs($fp, 'test string') ;
flock($fp, LOCK_UN) ;
}
fclose($fp) ;
?>
파일에 락요청이 초당 20개 정도 들어올 경우 CPU 점유율 100%를 먹으면서 뻗어버리는 경우가 있기 때문에,
그에 대한 해법.
<?php
// waiting until file will be locked for writing (1000 milliseconds as timeout)
if ($fp = fopen($fileName, 'a')) {
$startTime = microtime();
do {
$canWrite = flock($fp, LOCK_EX);
// If lock not obtained sleep for 0 - 100 milliseconds, to avoid collision and CPU load
if(!$canWrite) usleep(round(rand(0, 100)*1000));
} while ((!$canWrite)and((microtime()-$startTime) < 1000));
//file was locked so now we can store information
if ($canWrite) {
fwrite($fp, $dataToSave);
}
fclose($fp);
}?>
// waiting until file will be locked for writing (1000 milliseconds as timeout)
if ($fp = fopen($fileName, 'a')) {
$startTime = microtime();
do {
$canWrite = flock($fp, LOCK_EX);
// If lock not obtained sleep for 0 - 100 milliseconds, to avoid collision and CPU load
if(!$canWrite) usleep(round(rand(0, 100)*1000));
} while ((!$canWrite)and((microtime()-$startTime) < 1000));
//file was locked so now we can store information
if ($canWrite) {
fwrite($fp, $dataToSave);
}
fclose($fp);
}?>
그 외에도 밑으로 쭉쭉쭉....
'PHP' 카테고리의 다른 글
PHP Application을 가장 빠르게 (0) | 2009.05.15 |
---|---|
URLEncode Code Chart (0) | 2009.05.15 |
정규표현식 (0) | 2009.05.06 |
php.ini disable_functions (0) | 2009.05.06 |
인코딩 체크 (0) | 2009.05.03 |