teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

Event.wait を使ったサンプルを削除。誤誘導になる為 / 追記: 2つのスレッドで実装

2021/06/25 04:17

投稿

teamikl
teamikl

スコア8817

answer CHANGED
@@ -31,42 +31,33 @@
31
31
   → tkinterでキー入力を拾い、別スレッドへ通知
32
32
 
33
33
  ----
34
- ボタンによる別スレッドの停止のデモ (threading.Event の使い方サンプル)
35
- ```python
36
- import tkinter as tk
37
- import threading
34
+ 解説: 2つのスレッドで実装する
38
- import time
39
35
 
36
+ 問題点:
37
+ Lockで排他制御する場合、GUI等のイベント駆動プログラミングでは
38
+ ロック獲得によるブロックが発生すると、ウィンドウのフリーズに繋がる為、
39
+ 避ける傾向があります。
40
40
 
41
- def slideshow(event):
41
+ 解決策: 代案としては、プログラムの構造自体を
42
- # スライドショーの代替として
43
- while True:
44
- event.wait() # ボタンが押されるとここで止る / も一度で再開
42
+ リソース毎に担当のスレッドを決めて、そのリソースは担当のスレッドからしか操作しないよに、
45
- print("tick") # ループが稼働るの確認る為に表示
43
+ 外部から操作した場合は、queue 等用いてスレッド間の通信で行う、としま
46
- time.sleep(0.5)
44
+ 今回のケースであれば、対象のリソースは tkinter と cv2 の2つに別ける。
47
45
 
48
- pause = threading.Event()
46
+ ![イメージ説明](f8d72b3b9b2159caddabae3c56e70d4f.png)
49
- pause.set()
50
47
 
48
+ 起動時
49
+ - Sub(cv2): 準備後に、tkinter起動を待機 `tk_started.wait()`
50
+ - Main(tk): tkinter を起動
51
+ - Main(tk): イベントループを開始。tk_started.set() で Subスレッドの待機を解除
52
+ - Sub(cv2): イベントループ開始。スライドショー
51
53
 
52
- thread = threading.Thread(
54
+ 停止処理
53
- target=slideshow, args=(event,), daemon=True)
55
+ - Main(tk): shared.pause = True
56
+ - Sub(cv2): c2.waitKey(1) を呼び続けるループに入る(イベントループ継続の為)
54
57
 
55
- def click(e):
58
+ 終了処理
56
- if event.is_set():
59
+ - Main(tk): shared.running = sharead.pause = False (停止状態解除と稼働フラグをオフに)
57
- e.widget.config(text="start")
60
+ - Sub(cv2): フラグがオフになったことにより、イベントループを抜けて終了
58
- pause.clear()
59
- else:
60
- e.widget.config(text="stop")
61
- pause.set()
62
61
 
63
- root = tk.Tk()
62
+ ----
64
- button = tk.Button(root, text="stop")
63
+ 訂正: ~~ボタンによる別スレッドの停止のデモ (threading.Event の使い方サンプル)~~
65
- button.bind("<Button-1>", click)
66
- button.pack()
67
- root.after_idle(thread.start)
68
- root.mainloop()
69
- ```
70
-
71
- 注意: event.wait() はイベントループ内では使わない事。
72
- マウス・キー入力が処理できなくてウィンドウがフリーズします。

1

補足

2021/06/25 04:17

投稿

teamikl
teamikl

スコア8817

answer CHANGED
@@ -28,7 +28,7 @@
28
28
   ※ cv2 のバックエンド次第では、メインスレッドで使わないといけないような制限がある事もあるかもしれません。
29
29
   その場合は、tkinterをサブスレッドで使うか、マルチプロセスにする。
30
30
  - cv2.waitKey 等は入力所得が競合する為、何らかの対策が必要です。
31
-  → tkinterでキー入力を拾い、別スレッドへはthreading.Event を使い通知
31
+  → tkinterでキー入力を拾い、別スレッドへ通知
32
32
 
33
33
  ----
34
34
  ボタンによる別スレッドの停止のデモ (threading.Event の使い方サンプル)
@@ -66,4 +66,7 @@
66
66
  button.pack()
67
67
  root.after_idle(thread.start)
68
68
  root.mainloop()
69
- ```
69
+ ```
70
+
71
+ 注意: event.wait() はイベントループ内では使わない事。
72
+ マウス・キー入力が処理できなくてウィンドウがフリーズします。