1. Read and Write locks are distinguished.
If a write lock is used each time, multiple processes will be queued to read one file. This is definitely not efficient.
2. distinguish between blocking and non-blocking modes.
In general, if a process is writing a file, another process should be blocked. However, many times, we can do something else first,
Then, you can determine whether another person is writing a file. If not, add data to the file, which is more efficient.
3. Fixed the bug of locking files on Linux, especially on the GFS file system.
CodeAs follows:
Copy code The Code is as follows: <? PHP
Class file_lock
{
Private $ name;
Private $ handle;
Private $ mode;
Function _ construct ($ filename, $ mode = 'a + B ')
{
Global $ php_errormsg;
$ This-> name = $ filename;
$ Path = dirname ($ this-> name );
If ($ Path = '.' |! Is_dir ($ PATH )){
Global $ config_file_lock_path;
$ This-> name = str_replace (Array ("/", "\"), array ("_", "_"), $ this-> name );
If ($ config_file_lock_path = NULL ){
$ This-> name = dirname (_ file _). "/lock/". $ this-> name;
} Else {
$ This-> name = $ config_file_lock_path. "/". $ this-> name;
}
}
$ This-> mode = $ mode;
$ This-> handle = @ fopen ($ this-> name, $ mode );
If ($ this-> handle = false ){
Throw new exception ($ php_errormsg );
}
}
Public Function close ()
{
If ($ this-> handle! = NULL ){
@ Fclose ($ this-> handle );
$ This-> handle = NULL;
}
}
Public Function _ destruct ()
{
$ This-> close ();
}
Public Function lock ($ locktype, $ nonblockinglock = false)
{
If ($ nonblockinglock ){
Return flock ($ this-> handle, $ locktype | lock_nb );
} Else {
Return flock ($ this-> handle, $ locktype );
}
}
Public Function readlock ()
{
Return $ this-> lock (lock_sh );
}
Public Function writelock ($ wait= 0.1)
{
$ Starttime = microtime (true );
$ Canwrite = false;
Do {
$ Canwrite = flock ($ this-> handle, lock_ex );
If (! $ Canwrite ){
Usleep (RAND (10,100 0 ));
}
} While ((! $ Canwrite) & (microtime (true)-$ starttime) <$ wait ));
}
/**
* If you want to log the number under multi-thread system,
* Please open the lock, use a + mod. Then fopen the file will not
* Destroy the data.
*
* This function increment a Delt value, and save to the file.
*
* @ Param int $ delt
* @ Return int
*/
Public Function increment ($ delt = 1)
{
$ N = $ this-> get ();
$ N + = $ delt;
$ This-> set ($ N );
Return $ N;
}
Public Function get ()
{
Fseek ($ this-> handle, 0 );
Return (INT) fgets ($ this-> handle );
}
Public Function set ($ value)
{
Ftruncate ($ this-> handle, 0 );
Return fwrite ($ this-> handle, (string) $ value );
}
Public Function unlock ()
{
If ($ this-> handle! = NULL ){
Return flock ($ this-> handle, lock_un );
} Else {
Return true;
}
}
}
?>
Test code:Copy codeThe Code is as follows: <? PHP
/**
* Write lock test
* Open thread 1
*/
Require ("file_lock.php ");
$ Lock = new file_lock (dirname (_ file _). "/filelock. Lock ");
/** The lock speed of a single thread is 30 thousand times per second. **/
/** Two threads write, 20 thousand of the data is about 7 S */
/** Write data in one thread. The data size of 10 thousand is about 3.9 S. The two files are written at the same time, which is faster */
/** If the lock is not performed, it takes about 2.8 seconds for a process to write data. Locking is costly. */
/** Do not lock, the two processes are not evenly distributed, and most of them conflict */
$ Lock-> writelock ();
$ Lock-> increment ();
$ Lock-> unlock ();
While ($ lock-> get () <2 ){
Usleep (1000 );
}
Sleep (1 );
Echo "begin to runing \ n ";
$ T1 = microtime (true );
For ($ I = 0; I I <10000; $ I ++)
{
$ Lock-> writelock ();
$ Lock-> increment (1 );
$ Lock-> unlock ();
}
$ T2 = microtime (true)-$ T1;
Echo $ T2;
?>
I added an increment function to implement simple thread synchronization and allow two processes to execute some code at the same time. Of course, there is a certain error.
The error here is 0.001 S.
This class can be simply used in the previous memcache message queue to implement thread-safe message queues.