Next: , Previous: , Up: オペレーティングシステムのインターフェース   [Contents][Index]


41.11 遅延実行のためのタイマー

将来の特定時刻や特定の長さのアイドル時間経過後に関数を呼び出すためにタイマー(timer)をセットアップできます。タイマーは次回の呼び出し時刻と呼び出す関数についての情報を格納したスペシャルオブジェクトです。

Function: timerp object

この述語関数はobjectがタイマーなら非nilをリターンする。

EmacsはLispプログラム内では、任意の時点ではタイマーを実行できません。サブプロセスからの出力が受け入れ可能なときだけEmacsはタイマーを実行できます。つまり待機中や待機することが可能sit-forread-eventのような特定のプリミティブ関数内部でのみタイマーを実行できます。したがってEmacsがbusyならタイマーの実行は遅延するかもしれません。しかしEmacsがidleなら実行される時刻は非常に正確になります。

quitにより多くのタイマー関数が物事を不整合な状態に放置し得るので、ターマー関数呼び出し前にEmacsはinhibit-quittをバインドします。ほとんどのタイマー関数は多くの作業を行わないので、これは通常は問題にはなりません。しかし実際には実行に長時間を要する関数を呼び出すタイマーが問題となる恐れがあります。タイマー関数がquitを許容する必要があるならwith-local-quitを使用するべきです(quitを参照)。たとえば外部プロセスから出力を受け取るためにタイマー関数がaccept-process-outputを呼び出す場合には、外部プロセスのハング時のC-gを確実に機能させるために、その呼び出しをwith-local-quit内部にラップすべきです。

バッファー内容の変更のためにタイマー関数を呼び出すのは通常は悪いアイデアです。これを行うときには単一のアンドゥエントリーが巨大になるのを防ぐために、通常はバッファーの変更前後でundo-boundaryを呼び出して、タイマーによる変更とユーザーのコマンドによる変更を分離するべきです。

タイマー関数はsit-forのようなEmacsに待機を発生させるような関数(時間の経過や入力の待機を参照)の呼び出しも避けるべきです。その待機中に別のタイマー(同じタイマーとう可能性さえある)が実行され得るので、これは予測不可能な効果を導く恐れがあります。特定時間の経過後に処理される必要があるタイマー関数は、新たなタイマーをスケジュールしてこれを行うことができます。

タイマー関数がリモートファイルを処理する場合には、同一接続ですでに実行中のリモートファイル処理と競合する可能性があります。そのような競合が検出されると、結果はremote-file-errorエラーに格納されます(標準的なエラーを参照)。このようなエラーはタイマー関数のbodyでラップすることで保護する必要があります。

(ignore-error 'remote-file-error
  …)

マッチデータを変更するかもしれない関数を呼び出すタイマー関数はマッチデータの保存とリストアをするべきです。マッチデータの保存とリストアを参照してください。

Command: run-at-time time repeat function &rest args

これは時刻timeに引数argsで関数functionを呼び出すタイマーをセットアップする。repeatが数値(整数か浮動小数点数)ならタイマーはtime後の各repeat秒ごとに再実行されるようスケジュールされる。repeatnilならタイマーは1回だけ実行される。

timeには絶対時刻と相対時刻を指定できる。

絶対時刻は限定された種々フォーマットの文字列を使用して指定でき、すでに経過後の時刻であっても当日の時刻とみなされる。認識される形式は‘xxxx’、‘x:xx’、または‘xx:xx’ (軍用時間)、および‘xxam’、‘xxAM’、‘xxpm’、‘xxPM’、‘xx:xxam’、‘xx:xxAM’、‘xx:xxpm’、‘xx:xxPM’のいずれか。時と分の部分の区切りはコロンのかわりにピリオドも使用できる。

相対時刻は単位を付加した数字を文字列として指定する。たとえば:

1 min

現在時刻から1分後を表す。

1 min 5 sec

現在時刻から65秒後を表す。

1 min 2 sec 3 hour 4 day 5 week 6 fortnight 7 month 8 year

現在時刻から丁度103ヵ月123日10862秒後を表す。

相対time値にたいしてEmacsは月を正確に30日、年を正確に365.25とみなす。

有用なフォーマットのすべてが文字列という訳ではない。timeが数字(整数か浮動小数点数)なら秒で数えた相対時刻を指定する。encode-timeの結果はtimeにたいする絶対時刻の指定にも使用できる。

ほとんどの場合には、repeat最初に呼び出されている際には効果はなくtime単独で時刻を指定する。例外が1つありtimetならエポックからrepeatの倍数秒ごとに毎回そのタイマーが実行される。これはdisplay-timeのような関数にとって有用。

タイマーが実行されるべきタイミングでEmacsがCPUタイムを取得できなかった場合(たとえば別プロセス実行中のためシステムがビジーだったり、コンピューターがスリープ中やサスペンド中の場合)には、Emacsが再開されてアイドルになり次第タイマーが実行される。

関数run-at-timeはスケジュール済みの将来の特定アクションを識別するtime値をリターンする。cancel-timer(以下参照)の呼び出しにこの値を使用できる。

Command: run-with-timer secs repeat function &rest args

これは正にrun-at-time と同じだが、これは遅延を秒で指定する際の使用を意図している(パラメーターはrun-at-timeの説明を参照。ただしこの関数はtimesecsとして渡している)。

タイマーのリピートは名目上はrepeat秒ごとに毎回実行されますが、すべてのタイマー呼び出しは遅延する可能性があることを忘れないでください。1つの繰り返しの遅延が次の繰り返しに影響を与えることはありません。たとえば3回分のスケジュール済みのタイマー繰り返しをカバーするほどの計算等によりEmacsがbusyでも、それらは待機を開始して連続してそのタイマー関数が3回呼び出されることになります(それらの間の別のタイマー呼び出しは想定していない)。最後の呼び出しからn秒より短くならずにタイマーを再実行したい場合にはrepeat引数を使用しないでください。タイマー関数は、かわりにそのタイマーを明示的に再スケジュールするべきです。

User Option: timer-max-repeats

この変数の値は以前スケジュールされていた呼び出しが止むを得ずに遅延された際に、タイマー関数がリピートによりまとめて呼び出される最大の回数を指定する

Macro: with-timeout (seconds timeout-forms…) body…

bodyを実行するがseconds秒後に実行を諦める。タイムアップ前にbodyが終了したら、with-timeoutbody内の最後のフォームの値をリターンする。ただしタイムアウトによりbodyの実行が打ち切られた場合には、with-timeouttimeout-formsをすべて実行して最後のフォームの値をリターンする。

このマクロはseconds秒後に実行するタイマーをセットすることにより機能する。その時刻の前にbodyが終了したらそのタイマーを削除して、タイマーが実際に実行されたらbodyの実行を終了してからtimeout-formsを実行する。

Lispプログラムでは待機を行えるプリミティブをプログラムが呼び出している時のみタイマーを実行できるので、bodyが計算途中の間はwith-timeoutは実行を停止できない — そのプログラムがこれらのプリミティブのいずれかを呼び出したときのみ停止できる。そのためbodyで長時間の計算を行う場合ではなく、入力を待機する場合だけwith-timeoutを使用すること。

あまりに長時間応答を待機するのを避けるために、関数y-or-n-p-with-timeoutはタイマーを使用するシンプルな方法を提供します。Yes-or-Noによる問い合わせを参照してください。

Function: cancel-timer timer

これはtimerにたいして要求されたアクションをキャンセルする。ここでtimerはタイマーであること。これは通常は以前にrun-at-timerun-with-idle-timerがリターンしたものである。この関数はこれらの関数の1つの呼び出しの効果をキャンセルする。指定した時刻が到来しても特に何も起きないだろう。

list-timersコマンドはカレントでアクティブなすべてのタイマーをリストします。コマンドc (timer-list-cancel)はポイントのある行のタイマーをキャンセルします。コマンドS (tabulated-list-sort)を使用すれば、列でリストをソートできます。