This article mainly introduces the parsing of file locks, mutex locks, and read/write locks in PHP programs. it focuses on the examples used in the sync module and the pthreads module. For more information, see
File lock
The full name is advisory file lock, which is mentioned in the book. Such locks are common. for example, after mysql and php-fpm are started, a pid file records the process id, which is the file lock.
This lock can prevent repeated running of a process. for example, when using crontab, a task can be executed every minute, but the running time of this process may exceed one minute, if you do not use the process lock to resolve the conflict, the two processes will be executed together.
Another benefit of using the PID file lock is that the process can send a stop or restart signal to itself. For example, the command to restart php-fpm is
Kill-USR2 'cat/usr/local/php/var/run/php-fpm.pid'
Send the USR2 signal to the process recorded in the pid file. the signal belongs to process communication and will be extended.
The php interface is flock, which is detailed in this document. Let's take a look at the definition, bool flock (resource $ handle, int $ operation [, int & $ wouldblock]).
- $ Handle is a pointer to the file system. it is a resource typically created by fopen ). This means that a file must be opened when flock is used.
- $ Operation is the operation type.
- & $ Wouldblock: if the lock is blocked, this variable is set to 1.
It should be noted that this function is blocked by default. if you want to avoid blocking, you can add a bitmask LOCK_NB in operation. Next, let's test it.
$ 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); // release lock} else {echo "Cannot get pid lock. the process is already up \ n ";} fclose ($ fp );
Save as process. php and run php process. php &. then run php process. php again, and you will see the error message. Flock also has a shared lock, LOCK_SH.
Mutex lock and read/write lock
Mutex in sync module:
Mutex is a combination of mutual exclusion. Use pecl to install the sync module and pecl install sync. SyncMutex in this document has only two methods: lock and unlock. let's test the code directly. It is not written in IDE, so cs is ugly. ignore it.
$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();}
Save as 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
Here, sub-processes 0 and 1 are not necessarily in front of anyone. But there is always one that cannot be locked. Here, the SyncMutex: lock (int $ millisecond) parameter is millisecond, which indicates the blocking duration.-1 indicates infinite blocking.
Read/write lock in sync module:
The SyncReaderWriter method is similar to readlock, readunlock, writelock, and writeunlock. it can appear in pairs. If no test code is written, it should be consistent with Mutex code. you can replace the lock.
Events in the sync module:
It feels like a Cond in golang. wait () is blocked, and fire () is used to wake up a process with Event blocking. A good article introduces Cond. it can be seen that Cond is a fixed usage of the lock. The same is true for SyncEvent.
The example in the php document shows that the fire () method can be used in web applications.
Test Code on
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();}
Here, we intentionally write less than one fire (), so the program will be blocked, proving that fire () only wakes up one process at a time.
Pthreads module
Lock and unlock mutex:
Function:
pthread_mutex_lock (mutex) pthread_mutex_trylock (mutex) pthread_mutex_unlock (mutex)
Usage:
The thread uses the pthread_mutex_lock () function to lock the specified mutex variable. if the mutex variable has been locked by another thread, the call will block the thread until the mutex is unlocked.
Pthread_mutex_trylock () will attempt to lock a mutex. however, if the mutex is already locked, the routine will return immediately with a "busy" error code. this routine may be useful in pthread_mutex_trylock ().
Try to lock a mutex. However, if the mutex is locked, the program immediately returns a busy error value. This function is very useful to prevent deadlocks when their priorities change. The thread can use pthread_mutex_unlock () to unlock the mutex used by the thread. This function can be called when a thread is used to protect data and other threads need to obtain mutex to protect data. If any, an error occurs:
- The mutex has been unlocked.
- The mutex is occupied by another thread.
The mutex volume is not amazing. In fact, they are the "gentleman agreement" of the participating thread ". When writing code, be sure to properly lock and unlock the mutex.
Q: There are multiple threads waiting for the same lock mutex. when the mutex is unlocked, the thread will first lock the mutex?
A: Unless the thread uses the priority scheduling mechanism, the thread will be allocated by the system scheduler, and the thread will be the first to lock the mutex at random.
#include
#include
#include
#include
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; }
Semaphores
Semaphores in the sync module:
The SyncSemaphore document shows that, unlike Mutex, Semaphore can be obtained by multiple processes (or threads) at a time, while Mutex can only be obtained by one at a time. Therefore, in the SyncSemaphore constructor, a parameter specifies the number of processes that can be used to obtain the semaphore.
Public SyncSemaphore ::__ construct ([string $ name [, integer $ initialval [, bool $ autounlock]) is this $ 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();}
At this time, both processes can get the lock.
- Semaphores in the sysvsem module
- Sem_get create Semaphore
- Sem_remove delete semaphores (generally not used)
- Sem_acquire request to obtain the Semaphore
- Sem_release releases the semaphore. Used in pairs with 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();}
Here is a problem. The second parameter of sem_acquire () $ nowait is set to false by default, blocking. I set it to true. if the lock fails, the following sem_release will warn PHP Warning: sem_release (): SysV semaphore 4 (key 0x63000081) is not currently acquired in/home/jason/sysvsem. php on line 33. Therefore, the release operation must be executed when the lock is obtained. this problem is not found in the previous examples. if the lock is not obtained, the release execution will not report an error. Of course, it is better to appear in pairs to ensure that the locks are obtained and then release.
In addition, it is necessary to describe the parameters of the ftok method. The first file must be an existing and accessable file. Generally, the file in the project is used, and the second is a single character string. Returns an int.
The 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