php鎖機制
阿新 • • 發佈:2018-12-19
檔案鎖
class fileLock
{
private $fp = '';
private $filePath = '';
public function init($init=array())
{
// 檔案路徑
$this->path = \zc::get('path', 'lock');
// 生成檔案的粒度,為0時,只生成一個檔案
// 設定粒度 維持一定量連線
$this->hashNum = isset($init[0])?$init[0]:0;
//加鎖超時時間
$this ->wait = isset($init[1])?$init[1]:0.3;
// 開啟檔案的模式
// a+ 讀寫方式 指向尾部 b 表示二進位制
$this->mode = isset($init[2])?$init[2]:'a+b';
}
public function name($name)
{
if (isset($this->fp[$name])) {
return;
}
if ($this->hashNum == 0) {
$this->filePath = $this->path . DIRECTORY_SEPARATOR . $name;
} else {
$this->filePath = $this->path . DIRECTORY_SEPARATOR . $this->createLockFile($name, $this->hashNum);
}
$dir = dirname($this->filePath);
if (! is_dir ($dir)) {
\zc::make('file')->mkdirs($dir, 0777);
}
$this->fp[$name] = fopen($this->filePath, $this->mode);
if (! $this->fp[$name]) {
unset($this->fp[$name]);
throw new fileLock_Exception('The lock file "' . $name . '" open failed!', '100002');
}
}
private function createLockFile($name = 'test', $hashNum = 10)
{
$rand = mt_rand(1, $hashNum);
$crc = abs(crc32($name));
if ($crc & 0x80000000) {
$crc ^= 0xffffffff;
$crc += 1;
}
return $name . '_' . ($crc % $rand);
}
public function lock($name, $nonBlockingLock = true)
{
$this->name($name);
if ($nonBlockingLock){
//非阻塞
return flock($this->fp[$name], $lockType | LOCK_NB);
} else {
$startTime = microtime(true);
$canWrite = false;
do {
$canWrite = flock($this->fp[$name], LOCK_EX);
if (! $canWrite) {
usleep(rand(10, 1000));
}
} while ((! $canWrite) && ((microtime(true) - $startTime) < $this->wait));
return $canWrite;
}
}
public function readLock($name)
{
$this->name($name);
return $this->lock($name, LOCK_SH);
}
public function unlock($name)
{
if ($this->fp[$name]) {
if (! flock($this->fp[$name], LOCK_UN)) {
return $this->unlock($name);
}
return true;
} else {
return true;
}
}
public function __destruct()
{
if (! empty($this->fp)) {
foreach ($this->fp as $k => $v) {
fclose($v);
unset($this->fp[$k]);
}
}
}
}
class fileLock_Exception extends \Exception
{
}
sem鎖
if (! function_exists('ftok')) {
function ftok($filename = "", $proj = "")
{
if (empty($filename) || ! file_exists($filename)) {
return - 1;
} else {
$filename = $filename . (string) $proj;
for ($key = array(); sizeof($key) < strlen($filename); $key[] = ord(substr($filename, sizeof($key), 1)));
return dechex(array_sum($key));
}
}
}
class semLock
{
private $sem_id = '';
private $filePath = '';
public function __construct()
{
$this->path = \zc::get('path', 'lock');
$this->hashNum = 0;
$this->mode = 'a+b';
$this->max_acquire = 1;
$this->perm = '0666';
}
public function set($key, $val = '')
{
if (is_array($key)) {
foreach ($key as $k => $v) {
$this->$k = $v;
}
} else {
$this->$key = $val;
}
return $this;
}
public function name($name)
{
if (isset($this->sem_id[$name])) {
return;
}
if ($this->hashNum == 0) {
$this->filePath = $this->path . DIRECTORY_SEPARATOR . $name;
} else {
$this->filePath = $this->path . DIRECTORY_SEPARATOR . $this->createLockFile($name, $this->hashNum);
}
$dir = dirname($this->filePath);
if (! is_dir($dir)) {
\zc::obj('file')->mkdirs($dir, 0777);
}
$key = ftok($this->filePath, $this->mode);
if ($key == - 1) {
throw new semLock_Exception('The lock file "' . $name . '" open failed!', '100002');
}
$this->sem_id[$name] = sem_get($key, $this->max_acquire, $this->perm);
if (! $this->sem_id[$name]) {
unset($this->sem_id[$name]);
throw new semLock_Exception('The sem id is empty!', '100003');
}
}
private function createLockFile($name = 'test', $hashNum = 10)
{
$rand = mt_rand(1, $hashNum);
$crc = abs(crc32($name));
if ($crc & 0x80000000) {
$crc ^= 0xffffffff;
$crc += 1;
}
return $name . '_' . ($crc % $rand);
}
public function lock($name, $nonBlockingLock = false)
{
$this->name($name);
return sem_acquire($this->sem_id[$name], $nonBlockingLock);
}
public function unlock($name)
{
if ($this->sem_id[$name]) {
if (! sem_release($this->sem_id[$name])) {
clearstatcache();
return $this->unlock($name);
}
return true;
} else {
return true;
}
}
function __destruct()
{
if (! empty($this->sem_id)) {
foreach ($this->sem_id as $k => $v) {
sem_remove($v);
unset($this->sem_id[$k]);
}
}
}
}
class semLock_Exception extends \Exception
{
}