在 php 中获取锁的最佳方法
我正在尝试更新APC中的变量,并且将有许多进程尝试这样做。
APC不提供锁定功能,所以我正在考虑使用其他机制...到目前为止,我发现的是mysql的GET_LOCK()和php的flock()。还有什么值得考虑的吗?
更新:我发现sem_acquire,但它似乎是一个阻塞锁。
我正在尝试更新APC中的变量,并且将有许多进程尝试这样做。
APC不提供锁定功能,所以我正在考虑使用其他机制...到目前为止,我发现的是mysql的GET_LOCK()和php的flock()。还有什么值得考虑的吗?
更新:我发现sem_acquire,但它似乎是一个阻塞锁。
/*
CLASS ExclusiveLock
Description
==================================================================
This is a pseudo implementation of mutex since php does not have
any thread synchronization objects
This class uses flock() as a base to provide locking functionality.
Lock will be released in following cases
1 - user calls unlock
2 - when this lock object gets deleted
3 - when request or script ends
==================================================================
Usage:
//get the lock
$lock = new ExclusiveLock( "mylock" );
//lock
if( $lock->lock( ) == FALSE )
error("Locking failed");
//--
//Do your work here
//--
//unlock
$lock->unlock();
===================================================================
*/
class ExclusiveLock
{
protected $key = null; //user given value
protected $file = null; //resource to lock
protected $own = FALSE; //have we locked resource
function __construct( $key )
{
$this->key = $key;
//create a new resource or get exisitng with same key
$this->file = fopen("$key.lockfile", 'w+');
}
function __destruct()
{
if( $this->own == TRUE )
$this->unlock( );
}
function lock( )
{
if( !flock($this->file, LOCK_EX | LOCK_NB))
{ //failed
$key = $this->key;
error_log("ExclusiveLock::acquire_lock FAILED to acquire lock [$key]");
return FALSE;
}
ftruncate($this->file, 0); // truncate file
//write something to just help debugging
fwrite( $this->file, "Locked\n");
fflush( $this->file );
$this->own = TRUE;
return TRUE; // success
}
function unlock( )
{
$key = $this->key;
if( $this->own == TRUE )
{
if( !flock($this->file, LOCK_UN) )
{ //failed
error_log("ExclusiveLock::lock FAILED to release lock [$key]");
return FALSE;
}
ftruncate($this->file, 0); // truncate file
//write something to just help debugging
fwrite( $this->file, "Unlocked\n");
fflush( $this->file );
$this->own = FALSE;
}
else
{
error_log("ExclusiveLock::unlock called on [$key] but its not acquired by caller");
}
return TRUE; // success
}
};
您可以使用apc_add函数来实现此目的,而无需诉诸文件系统或mysql。 仅当变量尚未存储时才成功;因此,提供了一种锁定机制。TTL可用于确保褪色的锁持有人不会永远保持锁定状态。apc_add
正确的解决方案的原因是因为它避免了检查锁定并将其设置为“由您锁定”之间存在的争用条件。由于仅在尚未设置值时才设置该值(将其“添加”到缓存中),因此它确保锁不能同时被两个调用获取,而不管它们在时间上的接近程度如何。没有一个解决方案不同时检查和设置锁定,本质上会受到这种竞争条件的影响;需要一个原子操作才能在没有争用条件的情况下成功锁定。apc_add
apc_add
由于APC锁仅存在于php执行的上下文中,因此它可能不是一般锁定的最佳解决方案,因为它不支持主机之间的锁定。 还提供了原子添加函数,因此也可以与此技术一起使用 - 这是主机之间锁定的一种方法。 还支持原子“SETNX”函数和TTL,是主机之间锁定和同步的非常常用的方法。Howerver,OP特别要求APC的解决方案。Memcache
Redis