在网上看到一道题,是这样问的,“写个函数来解决多线程同时读写一个文件的问题”
上边给的答案是:flock($hander,LOCK_EX)
这个我想了下,感觉很不解,flock锁住当前文件时(第一个进程还未写入完),当下一个进程访问的时候就能写入了么?所以做了下测试
写了两个文件
demo.php
<?
php
$fp = fopen ( ' asn.php ' , ' w+ ' );
flock ( $fp , LOCK_EX);
sleep ( 10 );
flock ( $fp , LOCK_UN);
fclose ( $fp );
?>
$fp = fopen ( ' asn.php ' , ' w+ ' );
flock ( $fp , LOCK_EX);
sleep ( 10 );
flock ( $fp , LOCK_UN);
fclose ( $fp );
?>
demo1.php
$fp
=
fopen
(
'
asn.php
'
,
'
w+
'
);
fwrite ( $fp , ' WriteOk! ' );
fclose ( $fp );
fwrite ( $fp , ' WriteOk! ' );
fclose ( $fp );
先运行,demo.php, 然后运行demo1.php,发现不能插入,所以依然质疑这个答案。
以前其实也遇到过这个问题,是个短信投票的接口,用了个不太主流的方法,当时也没出什么问题,可能是没到出错的量级吧。
function
add_num(
$file_path
,
$messageid
,
$num
){
$file_path_user = $file_path . ' / ' . $messageid ; // 把路径加上被投人ID,去往被投人的文件夹
while ( file_exists ( $file_path_user . ' /NO_WRITABLE ' )){}
// 为防止并发写入文件错误,判断一个文件是否存在,若存在证明正在插入,进入死循环,否则直接插入
touch ( $file_path_user . ' /NO_WRITABLE ' ); // 新建验证文件
file_put_contents ( $file_path_user . ' /num.txt ' ,
intval ( file_get_contents ( $file_path_user . ' /num.txt ' )) + $num
); // 增加票数
unlink ( $file_path_user . ' /NO_WRITABLE ' ); // 删除验证文件
}
$file_path_user = $file_path . ' / ' . $messageid ; // 把路径加上被投人ID,去往被投人的文件夹
while ( file_exists ( $file_path_user . ' /NO_WRITABLE ' )){}
// 为防止并发写入文件错误,判断一个文件是否存在,若存在证明正在插入,进入死循环,否则直接插入
touch ( $file_path_user . ' /NO_WRITABLE ' ); // 新建验证文件
file_put_contents ( $file_path_user . ' /num.txt ' ,
intval ( file_get_contents ( $file_path_user . ' /num.txt ' )) + $num
); // 增加票数
unlink ( $file_path_user . ' /NO_WRITABLE ' ); // 删除验证文件
}
这个方法用个新文件来标记是否插入完成,如果完成就插入正常插入下一条,如果没完成则进入死循环,这个需要把php文件的运行时间调高点(怕你插入的三国演义那种大东东,下一个进程会因为这个进程没结束而直至进行到php设置的最大运行时间而报错)
一个朋友说,可以在内存里做个标记,来替换掉文件标记,但试了半天不知道用什么方法实现。
希望那位知道的大侠回个可用的方法。我知道后也会更新此贴!