이 글에서는 주로 PHP 프로그램의 파일 잠금, 뮤텍스 잠금 및 읽기-쓰기 잠금 사용 기술을 소개하며, 동기화 모듈의 사용 예를 중점적으로 다루며 필요한 친구들이 참고할 수 있습니다. 그것이 모두에게 도움이 되기를 바랍니다.
파일 잠금
전체 이름은 책에 언급된 권고 파일 잠금입니다. 이러한 유형의 잠금은 비교적 일반적입니다. 예를 들어, mysql과 php-fpm이 시작된 후에는 프로세스 ID를 기록하는 pid 파일이 있습니다.
이 잠금을 사용하면 프로세스가 반복적으로 실행되는 것을 방지할 수 있습니다. 예를 들어 crontab을 사용하면 1분마다 하나의 작업이 실행되도록 제한되지만 프로세스 잠금을 사용하여 문제를 해결하지 않으면 이 프로세스가 1분 이상 실행될 수 있습니다. 충돌이 발생하여 두 프로세스를 함께 실행하면 문제가 발생합니다.
PID 파일 잠금 사용의 또 다른 장점은 프로세스가 중지 또는 다시 시작 신호를 자체적으로 보내는 것이 편리하다는 것입니다. 예를 들어 php-fpm을 다시 시작하는 명령은
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`
pid 파일에 기록된 프로세스에 USR2 신호를 보냅니다. 신호는 프로세스 통신에 속하며 별도로 처리됩니다.
PHP의 인터페이스는 매우 다양하며 문서는 비교적 자세합니다. 먼저 정의를 살펴보겠습니다. bool Flock (resource $handle , int $Operation [, int &$wouldblock ] ).
$handle은 일반적으로 fopen()에 의해 생성되는 리소스인 파일 시스템 포인터입니다. . 이는 Flock을 사용하려면 파일을 열어야 함을 의미합니다.
$Operation은 작업 유형입니다.
&$wouldblock 잠금이 차단되면 이 변수는 1로 설정됩니다.
이 기능은 기본적으로 차단된다는 점에 유의하세요. 작업에 대한 비트마스크 LOCK_NB를 내려서 테스트해 보세요.
$pid_file = "/tmp/process.pid"; $pid = posix_getpid(); $fp = fopen($pid_file, 'w+'); if(flock($fp, LOCK_EX | LOCK_NB)){ echo "got the lock \n"; ftruncate($fp, 0); // truncate file fwrite($fp, $pid); fflush($fp); // flush output before releasing the lock sleep(300); // long running process flock($fp, LOCK_UN); // 释放锁定 } else { echo "Cannot get pid lock. The process is already up \n"; } fclose($fp);
process.php로 저장하고 php process.php &를 실행한 다음 php process.php를 다시 실행하면 오류 메시지가 표시됩니다. Flock에는 공유 잠금인 LOCK_SH도 있습니다.
뮤텍스 잠금 및 읽기-쓰기 잠금
동기화 모듈의 뮤텍스:
Mutex는 복합어, 상호 배제입니다. pecl을 사용하여 동기화 모듈을 설치하고 pecl install sync를 설치합니다. 문서의 SyncMutex에는 잠금 및 잠금 해제 두 가지 메서드만 있습니다. 바로 코드 테스트로 이동하겠습니다. 저는 IDE에서 작성하지 않았으므로 cs가 매우 추악합니다. 무시하십시오.
$mutex = new SyncMutex("UniqueName"); for($i=0; $i<2; $i++){ $pid = pcntl_fork(); if($pid <0){ die("fork failed"); }elseif ($pid>0){ echo "parent process \n"; }else{ echo "child process {$i} is born. \n"; obtainLock($mutex, $i); } } while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo "Child $status completed\n"; } function obtainLock ($mutex, $i){ echo "process {$i} is getting the mutex \n"; $res = $mutex->lock(200); sleep(1); if (!$res){ echo "process {$i} unable to lock mutex. \n"; }else{ echo "process {$i} successfully got the mutex \n"; $mutex->unlock(); } exit(); }
mutex.php로 저장하고 php mutex.php를 실행하면 출력은
parent process parent process child process 1 is born. process 1 is getting the mutex child process 0 is born. process 0 is getting the mutex process 1 successfully got the mutex Child 0 completed process 0 unable to lock mutex. Child 0 completed
여기서 하위 프로세스 0과 1이 반드시 앞에 올 필요는 없습니다. 그러나 자물쇠를 얻지 못하는 사람은 항상 있습니다. 여기서 SyncMutex::lock(int $millisecond)의 매개변수는 차단 기간을 나타내는 밀리초이고, -1은 무제한 차단을 의미합니다.
동기화 모듈의 읽기-쓰기 잠금:
SyncReaderWriter의 메서드는 유사하며, readlock, readunlock, writelock, writeunlock이 쌍으로 나타날 수 있습니다. 작성된 테스트 코드는 없습니다. 자물쇠를 교체하십시오.
동기화 모듈의 이벤트:
golang의 Cond와 더 비슷하고, wait() 블록과 fire()는 Event에 의해 차단된 프로세스를 깨웁니다. Cond를 소개하는 좋은 기사가 있습니다. Cond는 고정된 잠금 사용법임을 알 수 있습니다. SyncEvent도 마찬가지입니다.
PHP 문서의 예는 fire() 메소드가 웹 애플리케이션에서 사용되는 것으로 보입니다.
for($i=0; $i<3; $i++){ $pid = pcntl_fork(); if($pid <0){ die("fork failed"); }elseif ($pid>0){ //echo "parent process \n"; }else{ echo "child process {$i} is born. \n"; switch ($i) { case 0: wait(); break; case 1: wait(); break; case 2: sleep(1); fire(); break; } } } while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo "Child $status completed\n"; } function wait(){ $event = new SyncEvent("UniqueName"); echo "before waiting. \n"; $event->wait(); echo "after waiting. \n"; exit(); } function fire(){ $event = new SyncEvent("UniqueName"); $event->fire(); exit(); }
의 테스트 코드 여기에는 의도적으로 fire()가 하나 덜 작성되어 프로그램이 차단됩니다. 이는 fire()가 한 번에 하나의 프로세스만 깨운다는 것을 증명합니다.
pthreads 모듈
뮤텍스 잠금 및 잠금 해제:
기능:
pthread_mutex_lock (mutex) pthread_mutex_trylock (mutex) pthread_mutex_unlock (mutex)
사용법:
뮤텍스가 다른 스레드에 의해 잠긴 경우 스레드는 pthread_mutex_lock() 함수를 사용하여 지정된 뮤텍스 변수를 잠급니다. , 이 호출은 뮤텍스가 잠금 해제될 때까지 스레드를 차단합니다.
pthread_mutex_trylock()은 뮤텍스를 잠그려고 시도합니다. 그러나 뮤텍스가 이미 잠겨 있으면 루틴은 "busy" 오류 코드와 함께 즉시 반환됩니다. 이 루틴은 pthread_mutex_trylock()에서 유용할 수 있습니다.
Mutex. 뮤텍스가 잠겨 있으면 프로그램은 사용 중인 오류 값과 함께 즉시 반환됩니다. 이 기능은 우선순위 변경 시 교착상태를 방지하는 데 유용합니다. 스레드는 pthread_mutex_unlock()을 사용하여 자신이 차지하는 뮤텍스를 잠금 해제할 수 있습니다. 한 스레드가 보호된 데이터의 사용을 완료하고 다른 스레드가 보호된 데이터에 대해 작업하기 위해 뮤텍스를 얻으려고 할 때 이 함수를 호출할 수 있습니다. 다음 상황이 발생하면 오류가 발생합니다. 뮤텍스가 잠금 해제되었습니다. 뮤텍스가 다른 스레드에 의해 점유되었습니다. 이는 참여 스레드의 "신사 합의"입니다. 코드를 작성할 때 뮤텍스를 올바르게 잠그고 잠금 해제해야 합니다.
#include<stdlib.h> #include<stdio.h> #include<unistd.h> #include<pthread.h> typedef struct ct_sum { int sum; pthread_mutex_t lock; }ct_sum; void * add1(void *cnt) { pthread_mutex_lock(&(((ct_sum*)cnt)->lock)); for(int i=0; i < 50; i++) { (*(ct_sum*)cnt).sum += i; } pthread_mutex_unlock(&(((ct_sum*)cnt)->lock)); pthread_exit(NULL); return 0; } void * add2(void *cnt) { pthread_mutex_lock(&(((ct_sum*)cnt)->lock)); for(int i=50; i<101; i++) { (*(ct_sum*)cnt).sum += i; } pthread_mutex_unlock(&(((ct_sum*)cnt)->lock)); pthread_exit(NULL); return 0; } int main(void) { pthread_t ptid1, ptid2; ct_sum cnt; pthread_mutex_init(&(cnt.lock), NULL); cnt.sum=0; pthread_create(&ptid1, NULL, add1, &cnt); pthread_create(&ptid2, NULL, add2, &cnt); pthread_join(ptid1,NULL); pthread_join(ptid2,NULL); printf("sum %d\n", cnt.sum); pthread_mutex_destroy(&(cnt.lock)); return 0; }
信号量
sync模块中的信号量:
SyncSemaphore文档中显示,它和Mutex的不同之处,在于Semaphore一次可以被多个进程(或线程)得到,而Mutex一次只能被一个得到。所以在SyncSemaphore的构造函数中,有一个参数指定信号量可以被多少进程得到。
public SyncSemaphore::__construct ([ string $name [, integer $initialval [, bool $autounlock ]]] ) 就是这个$initialval (initial value)
$lock = new SyncSemaphore("UniqueName", 2); for($i=0; $i<2; $i++){ $pid = pcntl_fork(); if($pid <0){ die("fork failed"); }elseif ($pid>0){ echo "parent process \n"; }else{ echo "child process {$i} is born. \n"; obtainLock($lock, $i); } } while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo "Child $status completed\n"; } function obtainLock ($lock, $i){ echo "process {$i} is getting the lock \n"; $res = $lock->lock(200); sleep(1); if (!$res){ echo "process {$i} unable to lock lock. \n"; }else{ echo "process {$i} successfully got the lock \n"; $lock->unlock(); } exit(); }
这时候两个进程都能得到锁。
sysvsem模块中的信号量
sem_get 创建信号量
sem_remove 删除信号量(一般不用)
sem_acquire 请求得到信号量
sem_release 释放信号量。和 sem_acquire 成对使用。
$key = ftok('/tmp', 'c'); $sem = sem_get($key); for($i=0; $i<2; $i++){ $pid = pcntl_fork(); if($pid <0){ die("fork failed"); }elseif ($pid>0){ //echo "parent process \n"; }else{ echo "child process {$i} is born. \n"; obtainLock($sem, $i); } } while (pcntl_waitpid(0, $status) != -1) { $status = pcntl_wexitstatus($status); echo "Child $status completed\n"; } sem_remove($sem); // finally remove the sem function obtainLock ($sem, $i){ echo "process {$i} is getting the sem \n"; $res = sem_acquire($sem, true); sleep(1); if (!$res){ echo "process {$i} unable to get sem. \n"; }else{ echo "process {$i} successfully got the sem \n"; sem_release($sem); } exit(); }
这里有一个问题,sem_acquire()第二个参数$nowait默认为false,阻塞。我设为了true,如果得到锁失败,那么后面的sem_release会报警告 PHP Warning: sem_release(): SysV semaphore 4 (key 0x63000081) is not currently acquired in /home/jason/sysvsem.php on line 33, 所以这里的release操作必须放在得到锁的情况下执行,前面的几个例子中没有这个问题,没得到锁执行release也不会报错。当然最好还是成对出现,确保得到锁的情况下再release。
此外,ftok这个方法的参数有必要说明下,第一个 必须是existing, accessable的文件, 一般使用项目中的文件,第二个是单字符字符串。返回一个int。
输出为
parent process parent process child process 1 is born. process 1 is getting the mutex child process 0 is born. process 0 is getting the mutex process 1 successfully got the mutex Child 0 completed process 0 unable to lock mutex. Child 0 completed
相关推荐:
위 내용은 PHP의 파일 잠금, 뮤텍스 잠금 및 읽기-쓰기 잠금에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!