如何正确使用PHP5信号量?

时间:2016-10-11 12:02:14

标签: php semaphore

我有这个函数试图从缓存中读取一些值。但是如果值不存在,它应该调用备用源API并将新值保存到缓存中。但是,服务器非常重载,几乎每次当值不存在时,会创建一个请求(很多API调用),并且每个请求都会将新的值存储到缓存中。但是,我想要的是能够多次调用API,但只有一个进程/请求能够将其存储在缓存中:

function fetch_cache($key, $alternativeSource) {
    $redis = new Redis();
    $redis->pconnect(ENV_REDIS_HOST);
    $value = $redis->get($key);

    if( $value === NULL ) {
        $value = file_get_contents($alternativeSource);

        // here goes part that I need help with
        $semaphore = sem_get(6000, 1); // does this need to be called each time this function is called?
        if( $semaphore === FALSE ) {
            // This means I have failed to create semaphore?
        }

        if( sem_aquire($semaphore, true) ) {
            // we have aquired semaphore so here
            $redis->set($key, $value);
            sem_release($semaphore); // releasing lock
        }

        // This must be call because I have called sem_get()?
        sem_remove($semaphore);
    }

    return $value;
}

在PHP5中正确使用信号量吗?

2 个答案:

答案 0 :(得分:3)

简短回答

  1. 您不需要在fetch_cache功能中创建和删除信号量。将sem_get()放入初始化方法(例如__construct)。
  2. 您应该使用sem_remove()删除信号量,但需要使用清除方法(例如__destruct)。或者,您可能希望将它们保持更长时间 - 取决于应用程序的逻辑。
  3. 使用sem_acquire()获取锁定,使用sem_release()释放锁定。
  4. 描述

    sem_get()

    创建一组three信号量。

    底层C函数semget 不是原子。当两个进程尝试调用semget时,有可能race condition。因此,应在某些初始化过程中调用semget。 PHP扩展通过三个信号量克服了这个问题:

    信号量0 a.k.a. SYSVSEM_SEM

    初始化为sem_get' s $max_acquire并在进程获取时递减。

    调用sem_get的第一个进程获取SYSVSEM_USAGE信号量的值(见下文)。对于第一个流程,它等于1,因为具有原子semop的扩展sets it to 1semget之后正常运行。如果这确实是第一个过程,则扩展程序会将SYSVSEM_SEM信号量值分配给$max_acquire

    信号量1 a.k.a. SYSVSEM_USAGE

    使用信号量的进程数。

    Semaphore 2 a.k.a. SYSVSEM_SETVAL

    为内部SETVALGETVAL操作扮演锁定角色(请参阅man 2 semctl)。例如,当扩展程序将1设置为SYSVSEM_SEM时,它会设置为$max_acquire,然后重置为零。

    最后,sem_get将一个结构(包含信号量集ID,密钥和其他信息)包装到PHP资源中并返回它。

    所以你应该在一些初始化过程中调用它,当你只准备使用信号量时。

    sem_acquire()

    这是$max_acquire goes into play

    的地方

    SYSVSEM_SEM的值(让我们称之为semval)最初等于$max_acquiresemop()阻止semval阻止1大于或等于1。然后从semval中减去$max_acquire = 1

    如果semval,那么sem_acquire()在第一次通话后变为零,并且下一次拨打semval填空,直到通过sem_release()通话恢复$max_acquire

    当你需要获得下一个"锁定"从可用集(sem_release())。

    sem_acquire()

    SYSVSEM_SEM几乎相同,只是增加sem_acquire()的值。

    当您不再需要"锁定"先前使用sem_remove()获得。

    semop

    立即删除信号量集,唤醒集合中IPC_RMID中阻止的所有进程(来自ipcrm部分, SEMCTL(2)手册页。)

    所以这与使用<div class="contact-label span11 rights"> <div class="row-fluid"> <div class="span3"> <input type="checkbox" class="input-text" value="Y" name="contactpersonen_canorder_0" id="contactpersonen_canorder_0"></input> <label class="checkbox" for="contactpersonen_canorder_0">Mag border plaatsen</label> <input type="checkbox" class="input-text" value="Y" name="contactpersonen_canseestock_0" id="contactpersonen_canseestock_0"></input> <label class="checkbox" for="contactpersonen_canseestock_0">Mag gderen afhalen</label> </div> <div class="span3"> <input type="checkbox" class="input-text" value="Y" name="contactpersonen_canseeorders_0" id="contactpersonen_canseeorders_0"></input> <label class="checkbox" for="contactpersonen_canseeorders_0">Mag orders inzien</label> <input type="checkbox" class="input-text" value="Y" name="contactpersonen_canaddaddress_0" id="contactpersonen_canaddaddress_0"></input> <label class="checkbox" for="contactpersonen_canaddaddress_0">Mag bezorgadressen aanpassen</label> </div> <div class="span3"> <input type="checkbox" class="input-text" value="Y" name="contactpersonen_canseeprice_0" id="contactpersonen_canseeprice_0"></input> <label class="checkbox" for="contactpersonen_canseeprice_0">Mag netto prijs zien</label> <input type="checkbox" class="input-text" value="Y" name="contactpersonen_canseecredit_0" id="contactpersonen_canseecredit_0"></input> <label class="checkbox" for="contactpersonen_canseecredit_0">Mag facturen en creditfacturen inzien</label> </div> <div class="span3"> <input type="checkbox" class="input-text" value="Y" name="contactpersonen_canseepickup_0" id="contactpersonen_canseepickup_0"></input> <label class="checkbox" for="contactpersonen_canseepickup_0">Mag wijzigingen doorgeven</label> </div> </div> </div> 命令删除信号量实际上相同。

答案 1 :(得分:0)

您要执行的操作的文件权限应为 0666 ,而不是 6000