クリック

 
【内部トップページ】 へ移動します。



ご自分のホームページで、

 
同時アクセスによる 【データ破損】 に悩む人は、 コピーして お使い下さい。



【多重ロック処理】 の ソースコード です。 2重でも 3重でも 好きなだけ多重化して、 強固なロック処理ができます。

かなり優れたロック方式を考案したとしても、 100倍も強固になる訳ではありません。
同時に近いアクセスで、 他者プロセスが ロックをすり抜ける確率=100分の1 と仮定して、 ロックを 2重にすれば 【100分の1×100分の1】 になるでしょう。
 (単純に考えれば。)


本家サイトの 連動する 5つの 【CGI】 で、 16種類の 共有データを この 【多重ロック】 で読み書きしています。
 

#  ◆ロック処理サブルーチン
# 	$LockAction  …… ロックアクションモード・・【第1引数(flock用)】
# 	$LockingFile …… ロックファイル名・・・・・【第2引数】
#
#    ◆【戻り値】:
# 	ロック出来なかった場合は、ゼロ(0)
# 	ロック出来た場合は、 ロックした時の 【ロック処理履歴・情報-配列 の 添字ナンバー($lockCount)】(「何回目のロック処理か?」の値)
#
# 	$LockHandle[$lockCount]    …… ロックファイルの【ファイルハンドル(flock用)】
#
#	 ↑ ◆ファイルハンドルへのリファランス ・・【作成したファイルハンドルの“型グロブ”】へのポインタが代入され、保有する (flockロック成功時)。
sub lock {
	my $LockKey = $SymYesNo ;
	$lockbusy = 1;
		local ($LockAction)  = $_[0]; 			# ← 【第1引数】の受け取り
		local ($LockingFile) = $_[1]; 			# ← 【第2引数】の受け取り

		if (($LockKey != 1) && (-e $LockingFile)) {
			local($mtime) = (stat($LockingFile))[9];
		    if ($mtime && $mtime < time - 180) {
			if ($LockKey == 2) { unlink($LockingFile); } else { rmdir($LockingFile); }
		    }
		}
	$FileNumber++;
	$NewHandle = "$defHandle$FileNumber" ; 		# ← 【ファイルハンドル名】を生成 (flock用)

				# ↑ 多重ロック処理により  複数ロックファイルのオープン状態となるので、ロック毎に ファイルハンドル名を変える。
    LockBlock: {
		local($cnt) ;
	for ($cnt = 1; $cnt < 8; $cnt++) {
		if ($LockKey == 1) {
			if (open($NewHandle, ">$LockingFile")) {
				if (flock($NewHandle, $LockAction)) {
				    $lockflag++; 					# ← ロック中の“ロック数”を 1プラス。
				    $lockCount++; 					# ← 何回目のロック処理であるかを記憶。
					$Locked_File[$lockCount] = $LockingFile ;
					$Locked_Key[$lockCount]  = $LockKey ; 	# ← ◆ロック種別を配列に格納。
					$Locked[$lockCount] = 'yes' ; 	# ← 特定ロックファイルがロック中である“印”を 配列に格納。

					$LockHandle[$lockCount] = \*$NewHandle ; 	# ← ◆【型グロブ への リファランス】を配列に格納。
				    $lockbusy = 0 ;
				    last LockBlock;
				}
				else { close($NewHandle) ; sleep(1); }  # ← flock出来ない場合
			}
			else { sleep(1); next;  } 			   # ← open出来ない場合 (他のプロセスがロック中)
		}
		elsif ($LockKey == 2) {
			if (symlink(".", $LockingFile)) {
				$lockflag++; 					# ← ロック中の“ロック数”を 1プラス。
				$lockCount++; 					# ← 何回目のロック処理であるかを記憶。
					$Locked_File[$lockCount] = $LockingFile ; 	# ← ロックファイルのパスを配列に格納。
					$Locked_Key[$lockCount]  = $LockKey ; 	# ← ◆ロック種別を配列に格納。
					$Locked[$lockCount] = 'yes' ;
				$lockbusy = 0 ; 		   # ↑ 特定ロックファイルがロック中である“印”を 配列に格納。
				last LockBlock;
			}
			else { sleep(1); next; } 	   # ← シンボリックリンクを作成できない場合 (他のプロセスがロック中)
		}
		else {
			if (mkdir($LockingFile, 0755)) {
				$lockflag++; 					# ← ロック中の“ロック数”を 1プラス。
				$lockCount++; 					# ← 何回目のロック処理であるかを記憶。
					$Locked_File[$lockCount] = $LockingFile ; 	# ← ロックディレクトリのパスを配列に格納。
					$Locked_Key[$lockCount]  = $LockKey ; 	# ← ◆ロック種別を配列に格納。
					$Locked[$lockCount] = 'yes' ;
				$lockbusy = 0 ; 		   # ↑ 特定ロックファイルがロック中である“印”を 配列に格納。
				last LockBlock;
			}
			else { sleep(1); } 	   # ← ロック用ディレクトリを作成できない場合 (他のプロセスがロック中)
		}
	}
    }
      if ($lockbusy == 0) { $LockNumber = $lockCount ; } else { $LockNumber = 0 ; }
   return $LockNumber ;
}

# 		※【配列の特徴】: 同じロックfileでも、 成功すれば  単純に 情報を格納する(繰り返して)。
# 			$lockCountは ロックした通算回数。
# 		 【戻り値 $LockNumber】は、その時のロック処理が何回目であるか・・の数値。



★使用したい人は、 ここで コピーせず、 【使い方説明ページ】で コピーして下さい。
 
  【初期設定】 が必要です。 (最下部に リンクがあります。)



# =========================================================================
#  ◆ロック解除サブルーチン
# 	$unlockAction	…【第1引数】・・ ロックアクションモード(flock用)
# 	$unLockNumber	…【第2引数】・・ ロック解除すべきロックファイルの、【ロック処理履歴・情報-配列 の 添字ナンバー】
# 					    (「何回目のロック処理か?」の値)
#
# 	$LockHandle[$unLockNumber]  …… ロックファイルの【ファイルハンドル(flock用)】  ← 型グロブ への リファランス
# 	$Locked_File[$unLockNumber] …… ロックファイル
# 
# 		※ロックした時の“添字ナンバー”を頼りに  ロックファイルを特定し、ロック中である事を確認して そのロックだけを解除する。
#
sub unlock {
	my $LockKey = $SymYesNo ;

		local ($unlockAction)   = $_[0]; 		# ← 【第1引数】の受け取り
		local ($unLockNumber)   = $_[1]; 		# ← 【第2引数】の受け取り

    if (($lockflag != 0) && ($Locked_File[$unLockNumber] ne '') && ($Locked[$unLockNumber] eq 'yes')) {
	if ($LockKey == 1) {
		flock($LockHandle[$unLockNumber], $unlockAction) ;
		close($LockHandle[$unLockNumber]) ; 	# ← ↑ ◆配列に格納されている【型グロブ への リファランス】を利用して ロックを解除

	    $lockflag--; 				# ← ロック中の“ロック数”を 1マイナス。
	    $Locked[$unLockNumber] = 'free' ; 	# ← 特定ロックファイルがロック解除された“印”を 配列に格納。
	}
	elsif ($LockKey == 2) {
		if (-e $Locked_File[$unLockNumber]) {unlink($Locked_File[$unLockNumber]) ;}
									# ↑ ◆配列に格納されたロックファイルを特定し、ロックを解除

	    $lockflag--; 				# ← ロック中の“ロック数”を 1マイナス。
	    $Locked[$unLockNumber] = 'free' ; 	# ← 特定ロックファイルがロック解除された“印”を 配列に格納。
	}
	else {
		if (-e $Locked_File[$unLockNumber]) {rmdir($Locked_File[$unLockNumber]) ;}
								      # ↑ ◆配列に格納されたロックディレクトリを特定し、ロックを解除

	    $lockflag--; 				# ← ロック中の“ロック数”を 1マイナス。
	    $Locked[$unLockNumber] = 'free' ; 	# ← 特定ロックファイルがロック解除された“印”を 配列に格納。
	}
    }

}

# =========================================================================
#  ◆強制的に終了させる時 などに、1発で 【全ロック解除】するサブルーチン◆
#
sub ALLUnLock {
		if ($lockflag == 0) { return; }

		#  配列の各要素は、「特定ロックファイルの“最後のロック処理”が、通算で何回目のロック処理か?」の値を保有。

								#  	(ロック処理履歴・情報-配列 の 添字ナンバー)
					$dummy_LK = 0;
		@numberList_of_array = (
			$dummy_LK, $Sym_IP0_LK, $mini_IP0_LK, $Sym_0_LK, $mini_0_LK,
			$pwFile_pre_LK, $pwFile_LK, $Bigger_LK, $Sym_1i_LK, $mini_f_LK,
			$cokSrc_pre_LK, $mini_i_LK, $cokSrc_i_LK, $cokSrc_f_LK, $Sym_IP1_LK,
			$Sym_IP2_LK, $Sym_1_LK, $Sym_2_LK, $mini_IP1_LK, $mini_IP2_LK, $mini_1_LK,
			$mini_2_LK, $pastCNTmin_LK, $psIDwork, $LgdlchkGo, $pswCookREC, $psDateMgr,
			$dHjlIfI, $elHIjfItI
		) ;

	$ULK_Suu = 0;  local $LetUnLock[0] = 0 ;

	foreach $locked_number (@numberList_of_array) {

		    $n = $locked_number + 0;

		if (($n != 0) && ($Locked[$n] eq 'yes') && ($Locked_File[$n] ne '')) {

			$WiLLunLockNumber = $n ;  $ULK_Suu++;  $LetUnLock[$ULK_Suu] = $WiLLunLockNumber;

		    #  $LetUnLock[$ULK_Suu] は、アンロック対象の 新規_情報配列。

		    #  $WiLLunLockNumber は、【ロック処理履歴・情報-配列 の 添字ナンバー】
		}
	}

    if ($ULK_Suu > 0)  { &EachUnLock($ULK_Suu); }

    $lockflag = 0 ;
}

# =========================================================================

sub EachUnLock {
			# ALLUnLockからのみ呼ばれるサブルーチン。

    my($ULK_Suu) = $_[0];

    for ($L = 1; $L <= $ULK_Suu ; $L++) {

	$ULKnumber = $LetUnLock[$L];

	if ($Locked_Key[$ULKnumber] == 1) {
		flock($LockHandle[$ULKnumber], $mylockOFF);
		close($LockHandle[$ULKnumber]);
	    $Locked[$ULKnumber] = 'free' ;
	}
	elsif ($Locked_Key[$ULKnumber] == 2) {
		if (-e $Locked_File[$ULKnumber]) {unlink($Locked_File[$ULKnumber]) ;}
	    $Locked[$ULKnumber] = 'free' ;
	}
	else {
		if (-e $Locked_File[$ULKnumber]) {rmdir($Locked_File[$ULKnumber]) ;}
	    $Locked[$ULKnumber] = 'free' ;
	}
    }

}


『正しく 動作するか、 怪しい物だ・・・』 と思う人は、
 


【動作テスト】 の データ


『HPが壊れるから やめろ』・・・ って、 中傷好きの 2chネラーが言いそうですネ。





ちょっとした “アイデア” で工夫しただけですが、 確実に 効果があります。


5000 〜 6000アクセスは 楽勝です。


この時は、 【多重ロック】 も analysis.cgi も 未完成でしたが、 データ破損/障害はありませんでした。
 

 

 
(【analysis.cgi】 を起動するページの アクセス数。)


現在の 【analysis.cgi 月間アクセス数】  month_access.gif


完成 した今は、 80000アクセス (日) でも大丈夫です。

   ※共用の CGIサーバーが耐えられれば・・・ の話。 (笑)
     CGIサーバーが高負荷でダウンする状況は、 これは 【ロック処理】 の優劣ではなく、 サーバーの能力の話です。



以前 私が使用した 4種類の 【カウンターCGI】 は、 どれも 1日のアクセス数600程度で カウント記録ファイルが破損したりしました。
 
 (カウンターファイルを記録するだけなのに。)



  カウント記録ファイルが破損するのは ロックが破られている事になります。
  それとは別に、
  別種の 複数CGI同士で  共通のデータファイルを操作するのであれば、複数のロックファイルが 現実的に必要となります。


  また、どんなロック処理も、ロックの基本原理は 単純な仕組みです。↓

     ◇【ロックの基本原理】
	データファイルを読み書きする時に “あるファイル(ディレクトリ)が存在するか”を検査するように、
	【共通の取り決め】をしておき、全ての実行プログラムで 同一の手順で検査させる。
	そして、「もし存在すれば 他のプロセスが使用中である」と認識させて待たせる・・・これが基本原理です。
	従って、
	flock方式でも symlink方式でも mkdir方式でも、リネーム方式でも、
	共通の同一手順を踏んでくれない実行プログラムに対しては 【ロック効果=ゼロ】です。


      ◇初級の人のために付け加えます。

	例えば、
	【A】という掲示板CGIを入手し、【B】というパスワードマネージャを入手し、これを連動させる・・と仮定します。
	【A】のロックファイル設定で $lockfile = './myLokDir/hogehoge.lock'; という設定をし、
	【B】のロックファイル設定で $lockfile = './myLokDir/hogehoge.lock'; という同じ設定をした場合、
	AとBが 別のディレクトリに存在しているならば、
	A同士 または B同士ではロックされますが、
	AとB が同一のデータファイルに読み(書き)する時、 AとBでは  お互いに ロック機構が全く役に立っていません。
	なぜなら、
	AとBは 全く別のファイルを“ロックファイル(約束の検査ファイル)”として認識しているからです。


	Aファイルを読んだ内容によって Bファイルに特定の内容を書き込む・・という動作をする【実行プログラムA】が存在し、
	さらに別種の【実行プログラムB】が AファイルとBファイルを読んで動作を決定する・・
	こういう場合、AファイルとBファイルは その内容が同期している必要があります。
	ですから、【実行プログラムA】が Aファイルを読んでいる最中と 読んだ後は、
	【実行プログラムA】が Bファイルに書き込む動作が完了するまで、【実行プログラムB】には  Bファイルに手を出させてはいけません。

	かと言って、複数CGI同士で 多数のデータファイルを、1本のロックファイルで処理しようとすれば、
	待たされる時間が長くなるので、反応が悪くなったり、ロックビジーになりやすくなります。
	“同期させる必要の無い複数データファイル”は、 同一のロックファイルでロックする必要はありません。


★ページ先頭で紹介した【ロック・アンロック】のサブルーチンによって、
  データファイル群ごとに、“組”となるロックファイルを指定することによって、“多重ロック”をかけます。
  具体的には、
  データファイル群に対応させたロックファイル名を、ロックルーチンを呼ぶ時の【引数】として指定します。

  	※つまり、複数のロックファイルを使用する事になります。

★lock / unlock / ALLUnLock / EachUnLock の4本が 1セットで動作します。
  “ロックルーチンからの戻り値”を  “ロック解除ルーチンへの引数”として与える形で ロック解除ルーチンを呼ぶ
  という手順で、 複数ロックを実現しています。

★順不同に、歯抜け状態で【ロック・アンロック】をしても構いません。
    (処理の最後に  if ($lockflag != 0) { &ALLUnLock; }  を実行しておけば障害は発生しない。)

★ロックルーチンも ロック解除ルーチンも、
  受け取った【引数】以外に グローバル変数も参照しており、ロック時のデータを“配列”に格納する・・という動作ですので、
  【名前空間・変数値 が独立した 別パッケージ】から ロックルーチン/ロック解除ルーチン を利用する事はできません。
  (一般の 他のCGIと同様です。)
	※そのようにコーディングすれば可能ですが、
	  各パッケージに【ロックルーチン/ロック解除ルーチン の一式(4本)】を組み込んでしまった方が 簡単です。

★flockを使えないサーバーでは、【初期設定】の $lockkey設定で 他のロック方式を選択する事になります。




↓ ある有名サイトの、千数百円の 【シェウェア販売の カウンターCGI 】 の ロック処理部分です。


#  ロック処理
sub lock {
	local($retry) = 5;
	if (-e $LockFile) {
		local($accessTime) = (stat($LockFile))[9];
		if ($accessTime < time - 60) { &unlock; }
	}
	if ($LockKey == 1) {
		while (!symlink(".", $LockFile)) {
			if (--$retry <= 0) { &Errors; }
			sleep(1);
		}

	} elsif ($LockKey == 2) {
		while (!mkdir($LockFile, 0755)) {
			if (--$retry <= 0) { &Errors; }
			sleep(1);
		}
	}
	$LockFlag=1;
}

#  ロック解除
sub unlock {
	if ($LockKey == 1) { unlink($LockFile); }
	elsif ($LockKey == 2) { rmdir($LockFile); }
	$LockFlag=0;
}

# 	( これでは、ロックが破られても仕方ない。)



 
多重ロック 【使用例】 (初期設定などは、 【使い方】 の欄で。)


以下は、 このHPで稼動中の 【analysis.cgi】 からの抜粋です。 ( analysis.cgi の 【アクセス数】 は、 900/日。)

 
(いちばん多い所で、 5重のロック処理です。 サーバーが落ちない限り データ破損 しないでしょう。)


# 			◆◆ 【初期設定】の部分は、 ロック処理に関係する部分だけ 抜粋して掲載  ◆◆

# 			◆◆  先頭の【IP重複/連続アクセス対策】の処理部分は、 省略         ◆◆


★★★ ロック処理だけを クローズアップした【抜粋】です。 抜粋のままでは正常に動作しません。★★★



# ◆【初期設定】・・・・ ロック処理に関係する部分だけ 抜粋

# --------------------------------------
# 		◇ロック方式の種別・・・サーバーによって “使用不可のロック方式”もあるので、サーバー管理者に聞くか、
# 					ツールで調べるなりしてから選択して下さい。
# 
# ロック方式   1=flock関数  2=symlink関数  それ以外の数値=mkdir関数)(サーバー次第。)
$lockkey = 1;

# 	◆↓ 上の $lockkeyで設定できる値を選んで、好きな値(ロック形式)を設定する。
# 	  ↓       すると、プログラムコードで【$SymYesNo = $SymUsable;】を設定している間だけ $SymUsableで選択した方式でロックされる。
$SymUsable = 1;
# 	◆↑ symlinkを一時的に【共用】で使うなら、$SymUsableに 2を設定する。
# 	◆◆その場合は、全CGIで $SymUsable = 2; を設定するべし(そうしないと 別種CGI同士のロックが効かない)◆◆
# 
# --------------------------------------

# ◆↓全CGIで共通のロックファイル名・・◆【サブルーチン(lock・unlock)の第2引数】
# 
$Sym_0_lockfile = '/export/members/hogehoge/mySight/cgi-bin/MunyaSymDir/SymSym_0_lock.lock';
$mini_0_lockfile= '/export/members/hogehoge/mySight/cgi-bin/NormalLockDir/mini_0_normal.lock';
# 
# 〜〜 以下、省略。		★★★ ↑ この2行だけでは、以下の使用例は動作しません。★★★
# 
# --------------------------------------

# ◆ ↓ flock用のロックアクションモード・・【サブルーチン(lock・unlock)の第1引数】(変更してはならない)
		# 	◆symlink/mkdir関数 の場合も、ダミーで“引数設定”するべし。
		# 	◆unlockを呼ぶ時の 第1引数は、必ず  $mylockOFF (即ち 8)。
$otherReadOK = 1;  # ← ★【共有ロック(1)】を使うと、多重ロック不可能。
$otherGuard = 2;
$mylockOFF = 8;
# 		1 =共有ロック(他者の読み込みを許す) 2 =排他ロック(読み書き禁止)
# 		8 =ロック解除
# 
# --------------------------------------

# ◆ ロックファイル名と ペア(組み)になる【サブルーチン戻り値変数】

$Sym_IP0_LK =0; $mini_IP0_LK =0; $Sym_0_LK =0;      $mini_0_LK =0; $pwFile_pre_LK =0; $pwFile_LK =0;    $Bigger_LK =0;
$Sym_1i_LK =0;  $mini_f_LK =0;   $cokSrc_pre_LK =0; $mini_i_LK =0; $cokSrc_i_LK =0;   $cokSrc_f_LK =0;
$Sym_IP1_LK =0; $Sym_IP2_LK =0;  $Sym_1_LK =0;      $Sym_2_LK =0;  $mini_IP1_LK =0;   $mini_IP2_LK =0;
$mini_1_LK =0;  $mini_2_LK =0;

# 	 ===============================

$dummy_GIF = './images/dot_1.gif';



# 	 ===============================
# ◆初期値 の設定

# 	◆【ロック形式 初期値】の設定(通常設定)
$SymYesNo = $lockkey ;
$lockflag = 0 ;
# 		◆多重ロック処理で、$lockflagの値は 1か0ではなく、1プラスか 1マイナスされる。
# 	--------------
$lockCount  = 0 ;
# 		ロック処理を行った“通算の回数”
# 	--------------
# 	【ファイルハンドル名】の初期文字列
$defHandle = 'LCK' ;
$FileNumber = 0;
# 	--------------
# 		初期値 の設定
$Locked_File[0] = '' ;
$Locked_Key[0]  = 0 ;
$Locked[0] = '' ;
# 	 ===============================


require './sclrDataSave.pl';  # ← ◆書込ロックライブラリ の読み込み。


sub hiddenMain {

# 		【最終パス発行 年月日 + 分 記録ファイル】をチェック。


	    # ◆外ロック開始
	    $SymYesNo = $SymUsable; 		#  ← symlinkロックを指定できる。(◇◇◇)
	$Sym_0_LK = &lock($otherGuard, $Sym_0_lockfile);
			$SymYesNo = $lockkey;	#  ← symlink指定を解除。(◇◇◇)
		if ($Sym_0_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合


# ◆ロック開始・解除の 直前の【$SymYesNo = $SymUsable;】は、 別種のロック方式を一時的に変更して使い分けるための設定です。
# 
# 	(ロック開始・解除の 直後の【$SymYesNo = $lockkey;】は、 その設定を 通常設定に戻す処理です。)



#  現在の年月日分を判定。($nowDayTime_min と $nowMin を取得)

  &nowDayTimeMin_nowMin;

		# ◆内ロック開始
	$mini_0_LK = &lock($otherGuard, $mini_0_lockfile);
		if ($mini_0_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合


#  ◆不特定な時間帯に、【最終パス発行 年月日 + 分 記録ファイル】を 強制的に 上書き更新〜終了。(ファイル破損の対策)
# 	  (20分間)

# 		◇【 sData_save上書きモード指定】の場合は、書込み対象ファイル が読めない属性か否かは 関係なし。
# (1439-21=1418)
		$ForTime = &Rand_TIMEs(1418);  $ToTime = $ForTime + 21 ;

  if ($nowMin > $ForTime && $nowMin < $ToTime) {

  	   $wrMode = 'new';
  	  			#  (上書きモード)
  	$err = &sclrDataSave::sData_save($lastRegistYearMin_file, $nowDayTime_min, $wrMode, 0, 0);
     &pictureView;
  }


	  $Rec_accsess_min = $nowDayTime_min + 0;   # 初期値

# 		【最終パス発行 年月日 + 分 記録ファイル】を読みこむ

  if(open(IN,"$lastRegistYearMin_file")){
	  $Rec_accsess_min = ;
	  close(IN);
  }


# =====================================

	$Rec_accsess_min = $Rec_accsess_min + 0;


# 【最終パス発行人の 年月日 + 分】より  現在が 26分($how_min)以上“あと”であれば、
# 
# 	1.【最終パス発行 年月日 + 分 記録ファイル】を最初に更新する。
# 
# 	2.“パスワードIDを【自動発行】〜ファイル初期化〜上書きで書き込み”
# 
# 	3.【inTopクッキー元本ファイル】と【fr1クッキー元本ファイル】 も、検査。


	$how_min = $how_min + 0;

    $pastRec_min = $Rec_accsess_min + $how_min + 0;



  if ($nowDayTime_min > $pastRec_min) {


	# ◆外ロック開始
	$pwFile_pre_LK = &lock($otherGuard, $pwFile_pre_lockfile);
		if ($pwFile_pre_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合
	    # ◆内ロック開始
	    $pwFile_LK = &lock($otherGuard, $pwFile_lockfile);
	    	if ($pwFile_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合

	#  ============
	#  ID/パスワード を設定。
		@char = (0 .. 9, 'a' .. 'z', 'A' .. 'Z');

		# ID自動発行
		$id="";
		srand;
		foreach (1 .. 8) {
			$id .= $char[int(rand(@char))];
		}

		# パス自動発行
		$pw="";
		srand;
		foreach (1 .. 8) {
			$pw .= $char[int(rand(@char))];
		}

		# 暗号化
		$pw2 = &MyEncrypt($pw);
	#  ============

# 			◆◆ 少し 省略 ◆◆


# 	念のため、パスワードファイル自身の“更新時刻”を確認する。
# 	パスワード/IDファイルが 更新されて25分以内の新しい物であれば、終了。
	    $pw_mtime = (stat($pwdfile))[9];
	if ($pw_mtime && $pw_mtime > time - $how_min * 60) { &pictureView; }


# 	【最終パス発行 年月日 + 分 記録ファイル】を 上書き更新。

	&nowDayTimeMin_nowMin; 		#  $nowDayTime_min と $nowMin を取得
	    $wrMode = 'new';
	 $err = &sclrDataSave::sData_save($lastRegistYearMin_file, $nowDayTime_min, $wrMode, 0, 0);
			if ($err ne ""){ &Errors; }


# 	  =====	【最終パス発行 年月日 + 分 記録ファイル】の更新を完了。

# =======================


# 	パスワードファイルを初期化する。


# 			◆◆ 少し 省略 ◆◆


	  $writeData = "$id:$pw2\n";  $wrMode = 'new';

# 	  パスワード/IDファイル【標準】 上書き
	$err = &sclrDataSave::sData_save($pwdfile, $writeData, $wrMode, 0, 0);
	    if ($err ne ""){ &Errors; }
# 	  パスワード/IDファイル【その0】 上書き
	$err = &sclrDataSave::sData_save($pwd0file, $writeData, $wrMode, 0, 0);
	    if ($err ne ""){ &Errors; }
# 	  パスワード/IDファイル【その2】 上書き
	$err = &sclrDataSave::sData_save($pwd2file, $writeData, $wrMode, 0, 0);
	    if ($err ne ""){ &Errors; }

		# ◆内ロック解除
	    &unlock($mylockOFF, $pwFile_LK);

	# ◆外ロック解除
	&unlock($mylockOFF, $pwFile_pre_LK);


# 			◆◆ 少し 省略 ◆◆



# 	★★  ============ ★ 【inTopSureOpen.cgi】 との連動  ★ =========
# 	★★  ============ ★ 【fr1LoginCheck.cgi】との連動  ★ =========


	# ◆外ロック開始
		$SymYesNo = $SymUsable;			#  ← symlinkロック(2)を指定できる。(◇◇◇)
	$Sym_1i_LK = &lock($otherGuard, $Sym_1i_lockfile);
			$SymYesNo = $lockkey;	#  ← symlink指定を解除。(◇◇◇)
		if ($Sym_1i_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合

	   # ◆内ロック開始
	   $mini_i_LK = &lock($otherGuard, $mini_i_lockfile);
		if ($mini_i_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合
	   # ◆内ロック開始
	   $mini_f_LK = &lock($otherGuard, $mini_f_lockfile);
		if ($mini_f_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合


#  	=======================================

# 	★現在の“年月日時刻” を取得。(文字列)

	&nowTime_YearDayHour;

# 	【グローバル変数】で、 $nowTime と $YearDayHour を取得。 103120604 の形式。( 9ケタ。103年12月06日04時)

# 	============================

#  				◆先頭部のチェックのおかげで、
#  				  ここへ来た時は、すでに “25分に1回”の処理である。(前回アクセスの26分以上 あと。)

# 			◆◆ 少し 省略 ◆◆


# 	 不特定な時間帯に、【inTop年月日時刻  記録ファイル】と【fr1年月日時刻  記録ファイル】を 強制的に 上書き更新〜終了。
# 	  (35分間)
# 		↑ 現実的なアクセス間隔・・確率。 ファイル破損の対策。 防波堤ファイルでもある。
# 	(1439-36=1403)

	$ForTime = &Rand_TIMEs(1403);  $ToTime = $ForTime + 36 ;


	&nowDayTimeMin_nowMin; 	#  $nowDayTime_min と $nowMin を取得

	if ($nowMin > $ForTime && $nowMin < $ToTime) {

# 		【inTop年月日時刻  記録ファイル】を上書きする
			$wrMode = 'new';
		$err = &sclrDataSave::sData_save($YearDayHourRECfile, $nowTime, $wrMode, 0, 0);

# 		【fr1年月日時刻  記録ファイル】を上書きする
			$wrMode = 'new';
		$err = &sclrDataSave::sData_save($fr1YearDayHourRECfile, $nowTime, $wrMode, 0, 0);
	    &pictureView;
	}

# 				$nowTime と $YearDayHour を取得(文字列)
	&nowTime_YearDayHour;
	$RecTime = "1$nowTime";   # ◆初期値

# 	◆【inTop年月日時刻  記録ファイル】を読みこむ
	if(open(IN,"$YearDayHourRECfile")){
	    $RecTime = ;
	    close(IN);
	}

# 		◇“時刻 変わり”を認識したら、【inTop年月日時刻  記録ファイル】を更新して フラッグを立てる。

	if ($nowTime ne $RecTime) {

# 	   【inTop年月日時刻  記録ファイル】を上書きする  (“時刻 変わり”を認識)
		$wrMode = 'new';
	    $err = &sclrDataSave::sData_save($YearDayHourRECfile, $nowTime, $wrMode, 0, 0);
		if ($err ne ""){ &Errors; }

	    $YearDayHourfileNEW = 1;
				  # 【時刻 変わり】と【inTop年月日時刻  記録ファイル更新】のフラッグ
	}
	else { $YearDayHourfileNEW = 0; }


# 			◆◆ 途中 省略 ◆◆


	   # ◆内ロック解除
	   &unlock($mylockOFF, $mini_f_LK);
	   # ◆内ロック解除
	   &unlock($mylockOFF, $mini_i_LK);

	# ◆外ロック解除
	    $SymYesNo = $SymUsable; 		#  ← symlinkロック解除を指定。(◇◇◇)
	&unlock($mylockOFF, $Sym_1i_LK);
			$SymYesNo = $lockkey;	#  ← symlink指定を解除。(◇◇◇)


# 	=====================================



    # ◆外ロック開始
    $cokSrc_pre_LK = &lock($otherGuard, $cokSrc_pre_lockfile);
	if ($cokSrc_pre_LK == 0) { &pictureView; }		 #  ← ロック失敗の場合

	# ◆内ロック開始
	$cokSrc_i_LK = &lock($otherGuard, $cokSrc_i_lockfile);
		if ($cokSrc_i_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合
	# ◆内ロック開始
	$cokSrc_f_LK = &lock($otherGuard, $cokSrc_f_lockfile);
		if ($cokSrc_f_LK == 0) { &pictureView; }	 #  ← ロック失敗の場合


# 			◆◆ 途中 省略 ◆◆


    if (($YearDayHourfileNEW == 1) || ($cookSrcFileExist != 1)) {


# 	◇“時刻 変わり”を認識・・もしくは、【inTopクッキー元本ファイル】が存在しない。

# 	A・B・C・D・E 5個の【inTopクッキー元本ファイル】を更新。


# 			◆◆ 途中 省略 ◆◆


	    if(open(IN,"$rndCook_A_Sorcefile")){
		$rndCookData_A = ;
		close(IN);
	    }
	    if(open(IN,"$rndCook_B_Sorcefile")){
		$rndCookData_B = ;
		close(IN);
	    }
	    if(open(IN,"$rndCook_C_Sorcefile")){
		$rndCookData_C = ;
		close(IN);
	    }
	    if(open(IN,"$rndCook_D_Sorcefile")){
		$rndCookData_D = ;
		close(IN);
	    }

# 				 	$rndCookData_A は、【inTop乱数パスワードクッキー】に持たせるデータ。
	    $rndCookData_E = $rndCookData_D;
	    $rndCookData_D = $rndCookData_C;
	    $rndCookData_C = $rndCookData_B;
	    $rndCookData_B = $rndCookData_A;
	    $rndCookData_A = $pw_A;

# 	   	A・B・C・D・E 5個の【inTopクッキー元本ファイル】を上書きする

	    $wrMode = 'new';
	    $err = &sclrDataSave::sData_save($rndCook_A_Sorcefile, $rndCookData_A, $wrMode, 0, 0);
		if ($err ne ""){ &Errors; }
	    $err = &sclrDataSave::sData_save($rndCook_B_Sorcefile, $rndCookData_B, $wrMode, 0, 0);
		if ($err ne ""){ &Errors; }
	    $err = &sclrDataSave::sData_save($rndCook_C_Sorcefile, $rndCookData_C, $wrMode, 0, 0);
		if ($err ne ""){ &Errors; }
	    $err = &sclrDataSave::sData_save($rndCook_D_Sorcefile, $rndCookData_D, $wrMode, 0, 0);
		if ($err ne ""){ &Errors; }
	    $err = &sclrDataSave::sData_save($rndCook_E_Sorcefile, $rndCookData_E, $wrMode, 0, 0);
		if ($err ne ""){ &Errors; }
    }

# 			◆◆ 途中 省略 ◆◆


	# ◆内ロック解除
	&unlock($mylockOFF, $cokSrc_f_LK);
	# ◆内ロック解除
	&unlock($mylockOFF, $cokSrc_i_LK);

    # ◆外ロック解除
    &unlock($mylockOFF, $cokSrc_pre_LK);


# 			◆◆ 少し 省略 ◆◆


		# ◆内ロック解除
	    &unlock($mylockOFF, $mini_0_LK);

	    # ◆外ロック解除
	    $SymYesNo = $SymUsable; 		#  ← symlinkロック解除を指定。(◇◇◇)
	&unlock($mylockOFF, $Sym_0_LK);
			$SymYesNo = $lockkey;	#  ← symlink指定を解除。(◇◇◇)


&pictureView;

}

# ↑ hiddenMainサブルーチンの終り。



#-----------------#	◆◆ ロック処理・解除のサブルーチンは、最初に登場したので省略 ◆◆
# 				(その他のサブルーチンは、このページでは 省略)
#
#  1ドットのGIF画像を画面に表示。
#
sub pictureView {

    if ($lockflag != 0) { &ALLUnLock; }
  undef @Locked_File;

print "Content-type: image/gif\n\n";

$dummy_image = `/bin/cat $dummy_GIF`;

print "$dummy_image";

exit;
}
# 	================================================

上のソースコードは 大した事をしていませんが、
【多重ロック処理サブルーチン】 の使用例として、 下のリンク (使い方 説明ページ)で 全容を見る事ができます。



 
【sclrDataSave.pl】 について 少し触れておきます。
偶然 出会ったサイトの 秀逸なライブラリ (perl-lib.pl) から抜粋 〜 少しだけ 自分用にチューニングしたパッケージです。


sclrDataSave.pl は、【テンポラリーロック/ リネーム処理】 による書き込みを行います。

同じ上書きでも、 通常のような “ファイルオープン〜上書き” ではなく、 プロセス番号のテンポラリーfile に書き出して、
あとで リネーム しますから、
書き込む対象ファイルが 壊れていても関係なく 上書き出来ます。

  ※プロセステンポラリーファイルに対して 他のプロセスが読み書きする事は絶対にありません。


perl-lib.pl は無料ですが、 著作権に抵触するので sclrDataSave.pl として公開できません。
でも、 perl-lib.pl のままだと 55KBもあります。
perl-lib.pl は優れたライブラリです。 perl-lib.pl の 他のサブルーチンをいくつも利用するなら別ですが、
ロック処理に焦点を絞って考えた場合は、 【テンポラリーロック/ リネーム処理】 の部分を切り出す方が良いでしょう。
初級者のために、
どこを抜粋して どうするか、 下の 【ロック処理・解除 サブルーチン 使い方ページ】 で 説明します。


なお、 【テンポラリーロック/ リネーム方式】 の欠点という訳ではありませんが、
Aファイル と Bファイルを同期させる必要がある場合は、
【テンポラリーロック/ リネーム方式】 と 【A・Bファイル処理をサンドイッチ】する方式のロック処理を 併用する方が良いでしょう。
 (理由は 説明済み。)
【テンポラリーロック/ リネーム方式】で上書きすれば、 壊れたファイルも“自動修復”に近い書き込みとなります。


perl-lib.pl を提供されているサイトは 【Try The HomePage http://www.tryhp.net】 です。

  ※【Try The HomePage】 は 他にも 様々なツール/ライブラリを無料で提供なさっています。
    Perl の解説ページまであります。
    勉強にもなりますから、 ぜひ 訪問してみる事をオススメ します。(JavaScript = 有効 で訪問した方が良い。)





上の 【使用例】 を読んでいない人は、 ザーっと 【使用例】 を読んで下さい。


 
【ロック処理・解除 サブルーチン】 の使い方 と、 説明。



how_to_use_myLocking.htm





こちらも参考にして下さい。
 
   

【パスワード管理システム】