🪄 ホットスポット安定化の魔法 ― 第四の魔法 ― 分身の魔法
分身の魔法 ― 見張りと詠唱を切り離す

魔法シリーズ第四の魔法。前回はローテーションで使い魔が黙る話でしたが、ローテーション以外にも「聞き逃し」を生む呪いがありました。メインループが詠唱に縛られていたのです。
かかっていた呪い
カーチャンクに反応して音声応答を返す。ここまではいい。問題は、応答している最中に来た次の交信を取りこぼすこと。応答が混み合う時間帯ほど、反応が遅れたり、まるごと無視されたりしました。
呪いを追う
音声を合成して USRP へ送り出す一連の詠唱は、実測で約15秒かかります。当時はこれをメインスレッドでそのまま唱えていました。
# 旧き呪文:応答もメインループの中で唱える
while True:
line = f.readline()
if is_kerchunk(line):
speak_and_send(reply_wav) # ここで約15秒、見張りが完全停止speak_and_send() を唱えている15秒間、readline() には戻ってこないので、その間のログは一行も読まれません。応答中に来たアクセスは、ログを読み返した時には既に流れた後 ― だから聞き逃す。daemon 側の tgif_daemon.py でも同じ構図で、TGIF API 呼び出し(ネットワーク待ち)がメインループを縛り、その間 GPIO 処理やログ監視が止まっていました。
呪いの正体
時間のかかる詠唱(音声送出・ネットワーク I/O)を、見張りと同じ体で唱えていたこと。 見張りは「片時も止まらないこと」が務めなのに、重い詠唱に巻き込まれて固まっていました。
解呪の魔法
分身の魔法で、見張りと詠唱を切り離しました。本体(メインスレッド)はログの見張りと判定だけに専念し、片時も止まらない。重い詠唱は分身(ワーカースレッド)へ託します。
# 使い魔:応答を分身へ託す
def on_kerchunk():
threading.Thread(target=reply_worker, daemon=True).start()
# daemon:API 呼び出しを分身へ託す
def _do_restore(self):
threading.Thread(target=self._do_restore_actual, daemon=True).start()多重応答は避けたいので、is_talking のフラグを threading.Lock で守り、応答中に新たなカーチャンクが来ても現在の応答が終わるまで新規応答は出さない ― という元の作法はそのまま継承しました。
with talk_lock:
if is_talking:
return # 応答中なら何もしない
is_talking = True
# ... 応答の詠唱 ...
with talk_lock:
is_talking = Falseこれで本体の見張りは常時稼働となり、応答中の聞き逃しが消えました。
魔導書に記す
「見張る体」と「詠唱する体」は分ける。 見張りループの中に秒単位の詠唱を置いた瞬間、それは見張りでなくなります。重い詠唱は分身へ、共有の状態は Lock で守る。定石ですが、身をもって効力を確かめました。
次の魔法はもっと地味な、しかし見落としやすい呪い ― コールサイン正規表現の取りこぼしです。
📝 執筆:JJ2TAB(尾張旭 DMR デジピーター 管理人)
🏛 JJ2YYK あいちデジタルコミュニケーションハムクラブ
◀ 前へ:第三の魔法 ― inode を見抜く目 | 🪄 魔法シリーズ一覧 | 次へ:第五の魔法 ― /D を見逃さない魔法 ▶
1件のピンバック
🪄 ホットスポット安定化の魔法 ― 第三の魔法 ― inode を見抜く目 | JJ2YYK 尾張旭DMRデジピーター