如何正确使用PHP5信号灯?

我有这个功能,试图从缓存中读取一些值.但是,如果值不存在,则应调用备用源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是否正确使用了信号量?

解决方法:

简短答案

>您无需在fetch_cache函数中创建和删除信号量.将sem_get()放入初始化方法(例如__construct)中.
>您应该使用sem_remove()删除信号量,但是要使用清理方法(例如__destruct).或者,您可能希望将它们保留更长的时间-取决于应用程序的逻辑.
>使用sem_acquire()获取锁,然后使用sem_release()释放锁.

描述

sem_get()

创建一组three信号量.

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

信号量0亦称SYSVSEM_SEM

初始化为sem_get的$max_acquire,并在进程获取时递减.

第一个调用sem_get的进程将获取SYSVSEM_USAGEsemaphore的值(请参见下文).对于第一个过程,它等于1,因为扩展名sets it to 1在semget之后具有原子semop函数.并且,如果这确实是第一个过程,则扩展会将SYSVSEM_SEM信号量值分配给$max_acquire.

信号灯1又称SYSVSEM_USAGE

使用信号量的进程数.

信号量2又称SYSVSEM_SETVAL

充当内部SETVAL和GETVAL操作的锁(请参见man 2 semctl).例如,将其设置为1,而扩展名将SYSVSEM_SEM设置为$max_acquire,然后将其重置为零.

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

因此,当您仅准备使用信号量时,应该在一些初始化过程中调用它.

sem_acquire()

这是$max_acquire goes into play的位置.

SYSVSEM_SEM的值(我们称其为semval)最初等于$max_acquire. semop()阻塞,直到semval大于或等于1.然后从semval中减去1.

如果$max_acquire = 1,则在第一次调用之后semval变为零,并且对sem_acquire()的下一次调用将填充块,直到通过sem_release()调用恢复semval.

需要从可用集中($max_acquire)获取下一个“锁”时调用它.

sem_release()

与sem_acquire()几乎一样,只是它增加了SYSVSEM_SEM的值.

当您不再需要以前通过sem_acquire()获取的“锁”时调用它.

sem_remove()

立即删除信号量集,唤醒该集中的semop中阻塞的所有进程(来自IPC_RMID部分,SEMCTL(2)手册页).

因此,这实际上与使用ipcrm命令删除信号量相同.

上一篇:java-ConcurrentHashMap中基于番石榴的信号量与信号量


下一篇:可用的Java信号量允许使用ThreadPool