• ベストアンサー

.bat の同時起動を回避したい。

windows2008serverに、.batファイルを5個あります。これらは、同時に起動すると正常終了しない仕組みになっています。そのため、.bat の同時起動を回避したい。 それぞれの.batファイルの処理の前後関係は作ることは、避けたい。一つの処理が時間がかかると、次の処理が遅れてしまうからできません。 .batの同時実行を回避できるコマンド、もしくは、.batファイルのプログラムはあまりいじりたくはありません。 何か良い方法は、ありませんでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.6

何となく問題がわかった気がします。 ○5つの処理がある ○各処理の先頭に他と平行実行出来ない部分があり、その部分が重なるとエラーになる ○その先頭処理を過ぎた残りの部分の処理は他の処理と平行して実行可能である ○残りの部分の処理にかなり時間がかかるので、処理全体を待つことはしたくない でいいですか? その先頭部分というのが処理開始から10秒以内に終わるとします。下記のコードをバッチファイルの先頭に書くか、別ファイルにして call ファイル名.bat で呼び出してください。 :LOOP md \windows\temp\LOCK 2>NUL if %ERRORLEVEL%==0 goto OK ping -n 1 localhost >NUL goto LOOP :OK start /min cmd /c "ping -n 10 localhost > NUL & rd \windows\temp\LOCK" 仕組みとしては、 1. ロックファイルを作ってみる 2. 作れれば処理可能なので5へ 3. 作れなければ1秒待つ 4. 1へ戻る 5. 別プロセスで、「10秒待ってロックファイルを消す」という処理を走らせる  (この処理自体は10秒待つわけではない) 6. 本来の処理を始める 他の処理は、ロックを取れた処理が始まって10秒たてばロックファイルが消えるので、新たにロックが取れます。

takatai
質問者

補足

早速のご回答、まことにありがとうございます。 下記の条件となります。若干の差異がありますが、対応は可能でしょうか? ○5つの処理がある ⇒はい。 ○各処理の先頭に他と平行実行出来ない部分があり、その部分が重なるとエラーになる ⇒はい。先頭処理の開始時間だけをずらしたいだけで、先頭処理が途中から平行になっても問題はないです。  先頭処理で、最初にミリ秒のタイムスタンプ取得とSQLの実行ファイルを相手先システムに送付し、結果を受け取ります。  相手先システムで、「ミリ秒のタイムスタンプ」でキューイングするのですが、「ミリ秒のタイムスタンプ」が重なる相手先システムで処理が落ちて、結果が受け取れない。このため、先頭処理の、ミリ秒のタイムスタンプ取得をずらせればOKです。 ○その先頭処理を過ぎた残りの部分の処理は他の処理と平行して実行可能である ⇒はい。先頭処理の開始時間だけ、ずれればよい。開始時間だけずれれば、先頭処理の平行実行も可能です。  先頭の処理は、SQL実行が含まれているので処理時間はまちまちです。 ○残りの部分の処理にかなり時間がかかるので、処理全体を待つことはしたくない ⇒はい。他の処理が終わるのは、まちたくない。 (作成方法として) ・ロックファイルを作る以外に、制御できないでしょうか?  処理が正常終了しない場合、ロックファイルが残るので。 下記の部分で、ロックファイルを消すのは分かるのですが、万一10秒待っている間にこの処理が落ちると、ロックファイルがのこってしまう。 10秒というのは、先頭処理を10秒で終わる前提ですが、確実に終了する時間は分からない現状です。 また、先頭処理の開始時間だけをずらしたいだけで、先頭処理が途中から平行になっても問題はないです。 >5. 別プロセスで、「10秒待ってロックファイルを消す」という処理を走らせる > (この処理自体は10秒待つわけではない) なにとぞ、よろしくお願いいたします。

その他の回答 (7)

  • dscripty
  • ベストアンサー率51% (166/325)
回答No.8

ついに問題の核心↓を書いたね。 『相手先システムで、「ミリ秒のタイムスタンプ」でキューイングするのですが、「ミリ秒のタイムスタンプ」が重なる相手先システムで処理が落ちて、結果が受け取れない。』 タイムスタンプが同じだと、処理が失敗するなんて、どんな設計だよ! 同時が無理なら、何でミリ秒。。。?百歩ゆずってマイクロ秒! という突っ込みはおいといて、 解決案(A) - 開発会社にやらせる 『ジョブ管理ツール作成と基本的な管理の為のバッチファイル作成』がその「他の会社」との契約内容なら、やっつけ仕事もいいところだよ! 契約が切れていていても、瑕疵期間(たいてい 6ヶ月~1年ぐらいかな?)が設定されているかもしれないよ、上司に相談して契約内容を確認してみるのはどう? 解決案(B) - 自分で解決する。 「先頭処理で、最初にミリ秒のタイムスタンプ取得」するのなら、次の手順でその問題を回避できるよ。 同じタイムスタンプで 「SQLの実行ファイルを相手先システムに送付」しないように、取得したタイムスタンプを比較するために、TIMESTAMP.TXT というファイルを使うことにするよ。 1) 先頭処理で、取得したタイムスタンプと TIMESTAMP.TXT を比較して、同じなら、0.1秒以上待って、もう一度タイムスタンプを取得するところから始める。比較した結果が異なれば、2) へ進む。そもそも TIMESTAMP.TXT が存在しなければ、2) へ進む。 2) 今回取得したタイムスタンプを TIMESTANP.TXT へ保存する。 3) 処理を継続して、SQLの実行ファイルを相手先システムに送付する。 ちなみに、この解決方法も含めて [ANo.1] ~ [ANo.7] のやり方でも、100万回に 1回あるかないかわからないけれど、同じタイムスタンプで 「SQLの実行ファイルを相手先システムに送付」してしまう可能性は残るよ。 でも、失敗したときに、『ごめんなさい』で済むなら、運用上は問題ないかな。

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.7

新たにプログラムを開発しないでという条件だとロックファイルを作るしかないです。 Windowsの提供するロックの仕組みを使うプログラムを書いて、それに、ロックしたプロセスが死んでいたらロックを解除するとうのを組み込めば出来ます。 ジョブ管理ツールで、何かそのあたりを支援する仕組みはないのかな? >10秒というのは、先頭処理を10秒で終わる前提ですが、確実に終了する時間は分からない現状です。 バッチスクリプトからその重なって行けない処理の終了を知る手段があればそれをチェックすればいいです。無いのなら原理的に不可能。 ロックファイルの残っちゃう問題を、何とかするとすると、ロックファイルのタイムスタンプが10秒以上古い時は消しちゃうという処理かな。書くのめんどくさい。 ・ for %%F in (C:\windows\temp\LOCK) do set T=%%~tF で、%T% にロックファイルのタイムスタンプが取れます ・ 現在時刻は %DATE% と%TIME% を見ればわかります ・ それぞれを項目ごとに分解して、時*3600+分*60+秒 を求めて引き算して10と比べる。このあたりのやり方は、set /? で表示されます ということで前回書いた処理の前に、「ロックファイルが10秒以上古ければrdする」という処理を追加すればいいです。

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.5

>「他が処理中なら待つ」ではなく、「他が処理中なら実行する」といったところでしょうか。 何を実行する?他が実行中なら正常に実行出来ないという話だったのでは?? >5個のファイルから排他制御用を呼ぶ別のファイルを作成する。 5個のファイルとは? 別のファイルとは? >排他制御用ファイルには、切り替えスイッチのように時間をずらして実行できるように 時間をずらして実行する=待つ ですが? 論理的な文章を書くことを心がけてください。文章を書いた後で、読み返して、「これで他人に意味が伝わるか?」を冷静に考えてください。

takatai
質問者

補足

いろいろと、ご指摘ありがとうございます。 今までの説明のしかたが悪かったようです。 背景も含めて、説明します。 ジョブをコントロールしているジョブ管理ツールがあります。 このジョブ管理ツールで、ジョブの関係をコントロールしており、前のジョブが終わったら後続のジョブが起動するようになっています。 今は、前のジョブが終了したら、5個のジョブが起動するようにジョブ設計がされています。 この5個のジョブが同時刻で開始すると、1個のジョブだけ成功して、残りの4個が正常終了しないという状況になっています。 イメージとしては、下記のようなところです。 前の処理ZZの後処理に、下記5個のジョブがある。 前の処理ZZ→↓       A開始→→→→→→終了       B開始→終了       C開始→→→→→終了       D開始→→→→→→→→→終了       E開始→→→→終了 ジョブ管理ツールでは、前処理と後処理(AからE)の前後関係は作れますが、同時実行を回避することはできません。今回のAからEは、同時刻に開始するとジョブが正常終了しない形となっています。 ちなみに、AからEは、他の会社が作成したもので、できることなら変更を加えたくありません。また、その会社とは契約が切れていて、変更依頼できず、こちらで対応することになっています。 そこで、まず、次の対応しました。あまりやりたくなかったけれど、AからEの処理の先頭にtimeoutで5秒ずつずらす処理を埋め込みました。 しかし、AからEの処理には、ZZ以外に、それぞれ別の前処理がありました。そのそれぞれの前処理は処理時間が一定ではなく、いつ終了するのか分かりません。 そのため、timeoutで5秒ずつずらしても、AからEの処理開始が同時になる可能性があり、実際に同時に実行されることがあるのです。ありえないとは思いますが、発生しているのです。 ジョブの関係としては、次のイメージです。 ABEはtimeoutで5秒ずつずらすことで回避できるが、CDは回避できない。 前の処理ZZの後処理に、下記5個のジョブがある。 前の処理ZZ→→→→→→→→→→↓  Aの前処理→→→→→終了 ⇒A開始→→→→→→終了        :この場合、ABEが同時開始  Bの前処理→→終了   ⇒B開始→終了           :この場合、ABEが同時開始  Cの前処理→→→→→→→→→→→→→→→終了⇒C開始→→→→→終了   :この場合、CDが同時開始  Dの前処理→→→→→→→→→→→→→→→終了⇒D開始→→→→→→→→→終了 :この場合、CDが同時開始  Eの前処理→→→→→→終了⇒E開始→→→→終了         :この場合、ABEが同時開始 この状況のため、AからEの処理に、同時起動を制御するプログラムを埋め込むことを考えていますが、どのようにコーディングしていくといいかわかりません。 これまでのやり取りから、今考えているのは、 AからEの処理の代わりに、AからEのジョブには同じ排他制御プログラムを実行するように置き換える。 排他制御プログラムの中で、AからEのジョブを順番に実行するように切り替えるようして、開始時間を切り替えるのは、どうかなと思っています。 (変更後のイメージ) Aのジョブを排他制御プログラム実行置き換える。 Bのジョブを排他制御プログラム実行置き換える。 Cのジョブを排他制御プログラム実行置き換える。 Dのジョブを排他制御プログラム実行置き換える。 Eのジョブを排他制御プログラム実行置き換える。 排他制御プログラムでは、順番に、A~Eのプログラムを時間をずらして実行する。 ただ、この排他制御プログラム、AからEの処理を置き換える実行プログラムも作成できないスキルです。 この方法でいいのかも検討がついていません状態です。 なにとぞ、ソースプログラムを教えていただきたいところです。

  • dscripty
  • ベストアンサー率51% (166/325)
回答No.4

深呼吸を50回ぐらいして、そのあと読んでみて! ひとまず、補足質問の回答からだよ。 補足質問(1)の回答 「[テスト.bat] を [排他処理.bat]」 ではなくて、 「[テスト.bat]」を「[排他処理.bat]」にドラッグ&ドロップする。 補足質問(2)の回答 下のように、テスト.bat を引数として 排他処理.bat を実行すると、Call %* の部分で、テスト.bat が呼び出されるよ。 排他処理.bat テスト.bat 補足質問(3)の回答 排他処理.bat から テスト.bat を実行するんだから、テスト.bat から排他処理.bat を実行しないよ。 ここからは、感だけど > 同時実行を回避するだけにして、他の処理待ちにはできないんです。 この一行にすごく違和感があるから、どこか言葉の定義に食い違いがあるのかなと思って考えてみたよ。 何の断りもなく、「複数のバッチファイル」で「同時実行」を「回避したい」と言ったときは、下の様な意味だととらえるよ。 バッチファイルAが開始されたら、終了するまでは、他のバッチファイルの実行を回避したい。 バッチファイルAが終わったら、ようやくバッチファイルBが開始できる。 バッチファイルCはバッチファイルBの終了をまってようやく開始できる。 A開始→→→→→→終了    B待機→→→→→開始→終了      C待機→→→→→→→→開始→→→終了 もしかすると、「開始が同時になるのを回避したい」という意味かな? A開始→→→→→→終了 B開始→終了 C開始→→→終了 は、避けたいけど、 A開始→→→→→→終了    B開始→終了       C開始→→→終了 なら OK ということ? もし、この意味だとすると、5つのバッチファイルの中身を確認して、排他処理をする必要がある部分を特定しないと的確な回答はだせないとおもうな。

takatai
質問者

補足

ご回答ありがとうございます。深呼吸して、少し冷静になれました。 ありがとうございます。 5個のBatファイルの同時刻実行だけを回避したいのです。 「他が処理中なら待つ」ではなく、「他との起動時間だけをずらしたい」といったところでしょうか。 同時実行だけを回避したいので、5個のファイルから排他制御用を呼ぶ別のファイルを作成する。 排他制御用ファイルには、切り替えスイッチのように時間をずらして実行できるように なるといいと考えています。 ですので、最初に回答いただいた内容の排他制御において、5個のBatファイルの起動を切り替えるようなSwitch形式がいいかなと思い始めました。 >もしかすると、「開始が同時になるのを回避したい」という意味かな? >A開始→→→→→→終了 >B開始→終了 >C開始→→→終了 >は、避けたいけど、 >A開始→→→→→→終了 >   B開始→終了 >      C開始→→→終了 >なら OK ということ? >もし、この意味だとすると、5つのバッチファイルの中身を確認して、排他処理をする必要がある部分を特定しないと的確な回答はだせないとおもうな。 この「開始が同時になるのを回避したい」という意味になります。 排他制御で、Switchの形式で、A~Eの切り替えれるようにできればOKです。 5つのBatファイルから、排他制御.batを呼び出して、順番に5つのBatファイルを実行するようにするといいのでしょうか? そんなことはできるのでしょうか?

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.3

No1です。 >ただ、5個のBatファイルに、ご回答いただいた内容を埋め込むとした場合、他の処理が終了するのを待つことにならないでしょうか? 最初に書いた「他が処理中なら待つ」ならそうなります。 >同時実行を回避するだけにして、他の処理待ちにはできないんです。 回避してどうしたい?「他が処理中ならやめる」というのも書いておきましたけど???

takatai
質問者

補足

No1さん 再び、ありがとうございます。 >>ただ、5個のBatファイルに、ご回答いただいた内容を埋め込むとした場合、他の処理が終了するのを待つことにならないでしょうか? >最初に書いた「他が処理中なら待つ」ならそうなります。 >>同時実行を回避するだけにして、他の処理待ちにはできないんです。 >回避してどうしたい?「他が処理中ならやめる」というのも書いておきましたけど??? 5個のBatファイルの同時刻実行だけを回避したいのです。 「他が処理中なら待つ」ではなく、「他が処理中なら実行する」といったところでしょうか。 同時実行だけを回避したいので、5個のファイルから排他制御用を呼ぶ別のファイルを作成する。 排他制御用ファイルには、切り替えスイッチのように時間をずらして実行できるように なるといいと考えています。

  • dscripty
  • ベストアンサー率51% (166/325)
回答No.2

元のバッチファイルを変更しなくてもいいように、[ANo.1] さんの回答を少しアレンジしてみたよ。 下の [排他処理.bat] と [テスト.bat] を作成して、 [テスト.bat] を [排他処理.bat] に連続して何回かドラッグ&ドロップしてみて! [テスト.bat] が 5個のバッチファイルの代わりね。 [排他処理.bat] @Echo Off Set LOCKFILE=%~dpn0.lck :LOOP If Not Exist "%LOCKFILE%" Goto START_BAT Echo.↓が実行中のため10秒後に再実行 Type "%LOCKFILE%" Ping -n 10 localhost >nul Goto LOOP :START_BAT Echo.%1>"%LOCKFILE%" Call %* Del "%LOCKFILE%" [テスト.bat] ping -n 10 localhost

takatai
質問者

補足

ご回答ありがとうございます。 ちょっと意味が分からないところがあるので、次の3点をご質問させてください。 (1)この部分の、「[テスト.bat] を [排他処理.bat]」は、どこにドラッグ&ドロップするのでしょうか? >[テスト.bat] を [排他処理.bat] に連続して何回かドラッグ&ドロップしてみて! (2)[排他処理.bat]は、どこで、[テスト.bat]を実行させるのでしょうか? 下記のところでしょうか? Call %* (3)[テスト.bat]では、[排他処理.bat]をどこで実行させるのでしょうか? [テスト.bat] ping -n 10 localhost ????←ここに、[排他処理.bat]を実行させるのでしょうか? なにとぞ、よろしくお願いします。 かなり追い込まれています。。。

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.1

排他制御という奴ですね。「他が処理中なら待つ」なら、 :LOOP md \windows\temp\LOCK 2>NUL if %ERRORLEVEL%==0 goto OK ping -n 10 localhost >NUL goto LOOP :OK 処理内容をここに rd \windows\temp\LOCK 「他が処理中ならやめる」なら、 md \windows\temp\LOCK 2>NUL if not %ERRORLEVEL%==0 exit /b 処理内容をここに rd \windows\temp\LOCK ctrl-C で処理中断したり、処理中にWindows自体が落ちたりした場合は、LOCKディレクトリが残ってしまうので、別途、削除が必要です。

takatai
質問者

補足

ご回答ありがとうございます。 試してみます。 ただ、5個のBatファイルに、ご回答いただいた内容を埋め込むとした場合、他の処理が終了するのを待つことにならないでしょうか? 同時実行を回避するだけにして、他の処理待ちにはできないんです。 追加でご質問させてください。 かなり追い込まれていますので、なにとぞよろしくお願いします。

関連するQ&A