PHP编程中的锁
最近看了《理解Linux进程》这本开源书,链接。该书描述了linux中的进程概念,对锁和进程间通信(IPC)有一些总结。不过该书的描述语言是golang, 平时用的比较少,就想对应概念找找php中的接口。
文件锁
全名叫 advisory file lock, 书中有提及。 这类锁比较常见,例如 mysql, php-fpm 启动之后都会有一个pid文件记录了进程id,这个文件就是文件锁。
这个锁可以防止重复运行一个进程,例如在使用crontab时,限定每一分钟执行一个任务,但这个进程运行时间可能超过一分钟,如果不用进程锁解决冲突的话两个进程一起执行就会有问题。
使用PID文件锁还有一个好处,方便进程向自己发停止或者重启信号。例如重启php-fpm的命令为
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`
发送USR2信号给pid文件记录的进程,信号属于进程通信,会另开一个篇幅。
php的接口为flock,文档比较详细。先看一下定义,bool flock ( resource $handle , int $operation [, int &$wouldblock ] ).
$handle是文件系统指针,是典型地由 fopen() 创建的 resource(资源)。这就意味着使用flock必须打开一个文件。
$operation 是操作类型。
&$wouldblock 如果锁是阻塞的,那么这个变量会设为1.
需要注意的是,这个函数默认是阻塞的,如果想非阻塞可以在 operation 加一个 bitmask 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.
互斥锁和读写锁
sync模块中的Mutex
Mutex是一个组合词,mutual exclusion。用pecl安装一下sync模块, pecl install sync。 文档中的SyncMutex只有两个方法,lock 和 unlock, 我们就直接上代码测试吧。没有用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, run php mutex.php, output is
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 completedprocess 0 unable to lock mutex. Child 0 completed
这里子进程0和1不一定谁在前面。但是总有一个得不到锁。这里SyncMutex::lock(int $millisecond)的参数是 millisecond, 代表阻塞的时长, -1 为无限阻塞。
sync模块中的读写锁
SyncReaderWriter的方法类似,readlock, readunlock, writelock, writeunlock,成对出现即可,没有写测试代码,应该和Mutex的代码一致,把锁替换一下就可以。
sync模块中的Event
感觉和golang中的Cond比较像,wait()阻塞,fire()唤醒Event阻塞的一个进程。有一篇好文介绍了Cond, 可以看出Cond就是锁的一种固定用法。SyncEvent也一样。
php文档中的例子显示,fire()方法貌似可以用在web应用中。
上测试代码
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模块
貌似也看到了Mutex, Cond, Pool. 没来得及看,看完再补充。
信号量
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 semfunction 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 completedprocess 0 unable to lock mutex. Child 0 completed
最后,如果文中有错误的地方,希望大神指出,帮助一下菜鸟进步,谢谢各位。

What’s still popular is the ease of use, flexibility and a strong ecosystem. 1) Ease of use and simple syntax make it the first choice for beginners. 2) Closely integrated with web development, excellent interaction with HTTP requests and database. 3) The huge ecosystem provides a wealth of tools and libraries. 4) Active community and open source nature adapts them to new needs and technology trends.

PHP and Python are both high-level programming languages that are widely used in web development, data processing and automation tasks. 1.PHP is often used to build dynamic websites and content management systems, while Python is often used to build web frameworks and data science. 2.PHP uses echo to output content, Python uses print. 3. Both support object-oriented programming, but the syntax and keywords are different. 4. PHP supports weak type conversion, while Python is more stringent. 5. PHP performance optimization includes using OPcache and asynchronous programming, while Python uses cProfile and asynchronous programming.

PHP is mainly procedural programming, but also supports object-oriented programming (OOP); Python supports a variety of paradigms, including OOP, functional and procedural programming. PHP is suitable for web development, and Python is suitable for a variety of applications such as data analysis and machine learning.

PHP originated in 1994 and was developed by RasmusLerdorf. It was originally used to track website visitors and gradually evolved into a server-side scripting language and was widely used in web development. Python was developed by Guidovan Rossum in the late 1980s and was first released in 1991. It emphasizes code readability and simplicity, and is suitable for scientific computing, data analysis and other fields.

PHP is suitable for web development and rapid prototyping, and Python is suitable for data science and machine learning. 1.PHP is used for dynamic web development, with simple syntax and suitable for rapid development. 2. Python has concise syntax, is suitable for multiple fields, and has a strong library ecosystem.

PHP remains important in the modernization process because it supports a large number of websites and applications and adapts to development needs through frameworks. 1.PHP7 improves performance and introduces new features. 2. Modern frameworks such as Laravel, Symfony and CodeIgniter simplify development and improve code quality. 3. Performance optimization and best practices further improve application efficiency.

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP type prompts to improve code quality and readability. 1) Scalar type tips: Since PHP7.0, basic data types are allowed to be specified in function parameters, such as int, float, etc. 2) Return type prompt: Ensure the consistency of the function return value type. 3) Union type prompt: Since PHP8.0, multiple types are allowed to be specified in function parameters or return values. 4) Nullable type prompt: Allows to include null values and handle functions that may return null values.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SublimeText3 English version
Recommended: Win version, supports code prompts!

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

Dreamweaver Mac version
Visual web development tools

EditPlus Chinese cracked version
Small size, syntax highlighting, does not support code prompt function

SublimeText3 Mac version
God-level code editing software (SublimeText3)