当前位置:  开发笔记 > 编程语言 > 正文

在php中获取锁定的最佳方法

如何解决《在php中获取锁定的最佳方法》经验,为你挑选了3个好方法。

我正在尝试更新APC中的变量,并且将尝试执行此操作的许多进程.

APC不提供锁定功能,所以我正在考虑使用其他机制......到目前为止我发现的是mysql的GET_LOCK()和php的flock().还有什么值得考虑的吗?

更新:我找到了sem_acquire,但它似乎是一个阻塞锁.



1> harry..:
/*
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
    }
};


__destruct不会被致命的错误调用吗?我担心会导致锁被永久卡住并需要人工干预的情况

2> Daniel Farre..:

您可以使用apc_add函数来实现此目的,而无需使用文件系统或mysql. apc_add仅在变量尚未存储时才成功; 因此,提供了一种锁定机制.TTL可用于确保愚蠢的锁定器不会永远保持锁定状态.

原因apc_add是正确的解决方案是因为它避免了在检查锁定并将其设置为"由您锁定"之间存在的竞争条件.由于apc_add只设置了尚未设置的值(将其"添加"到缓存中),因此它确保一次两次调用无法获取锁定,无论它们是否及时接近.没有同时检查设置锁定的解决方案本身就会受到这种竞争条件的影响; 在没有竞争条件的情况下成功锁定需要一个原子操作.

由于APC锁定仅存在于php执行的上下文中,因此它可能不是一般锁定的最佳解决方案,因为它不支持主机之间的锁定. Memcache还提供了一个原子添加函数,因此也可以用于这种技术 - 这是一种在主机之间进行锁定的方法. Redis还支持原子'SETNX'函数和TTL,是一种非常常见的主机锁定和同步方法.然而,OP特别要求为APC提供解决方案.



3> Sean McSomet..:

如果锁定点是为了防止多个进程尝试填充空缓存键,为什么不想要阻塞锁?

  $value = apc_fetch($KEY);

  if ($value === FALSE) {
      shm_acquire($SEMAPHORE);

      $recheck_value = apc_fetch($KEY);
      if ($recheck_value !== FALSE) {
        $new_value = expensive_operation();
        apc_store($KEY, $new_value);
        $value = $new_value;
      } else {
        $value = $recheck_value;
      }

      shm_release($SEMAPHORE);
   }

如果缓存是好的,你只需滚动它.如果缓存中没有任何内容,则会获得锁定.一旦你有锁,你需要仔细检查缓存,以确保在等待锁定时,缓存没有重新填充.如果缓存已重新填充,请使用该值并释放锁定,否则,执行计算,填充缓存然后释放锁定.

推荐阅读
jerry613
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有