回答編集履歴

4

説明文の修正

2020/06/07 06:56

投稿

teamikl
teamikl

スコア8742

test CHANGED
@@ -64,7 +64,7 @@
64
64
 
65
65
  QThread を使う方法では、
66
66
 
67
- メインスレッドのイベントループを通じてシグナルを順番に処理する為、
67
+ メインスレッドのイベントループ順番に処理する為、
68
68
 
69
69
  同時アクセスは発生せずロックは不要です。(シグナル&スロットとイベントループを利用する恩恵)
70
70
 

3

リンクの修正と説明の追記(サンプルコードのロギングでスレッド名を表示)

2020/06/07 06:56

投稿

teamikl
teamikl

スコア8742

test CHANGED
@@ -36,13 +36,43 @@
36
36
 
37
37
 
38
38
 
39
- 追記: repl.it 上にコードを載せました。
39
+ ** [2020-06-07] 追記:** repl.it 上にコードを載せました。
40
40
 
41
41
  ソースコメント内の日本語は文字化けしますが、ブラウザ上で実行可能です。
42
42
 
43
43
 
44
44
 
45
+ ロギングでどのスレッドで実行されてるかを解るようにしたので、
46
+
47
+ **setCountがどのスレッドから実行されてるか辺りを着目してください**
48
+
49
+
50
+
51
+ - Python スレッド ... サブスレッドで実行(スレッドセーフでない)
52
+
53
+ - QThread スレッド ... メインスレッドで実行 (スレッドセーフ)
54
+
55
+
56
+
57
+ 前者の場合は、より安全にするなら追加でロック機構
58
+
59
+ 複数のスレッドから同時にアクセスさせないようにする仕組みの導入が必要です。
60
+
61
+ (このサンプルでは問題ありませんが、場合によってはプログラムがクラッシュしたりします)
62
+
63
+
64
+
65
+ QThread を使う方法では、
66
+
67
+ メインスレッドのイベントループを通じてシグナルを順番に処理する為、
68
+
69
+ 同時アクセスは発生せずロックは不要です。(シグナル&スロットとイベントループを利用する恩恵)
70
+
71
+
72
+
73
+
74
+
45
- https://repl.it/@MiKLTea/QThread-Demo
75
+ [[source on repl.it]](https://repl.it/@MiKLTea/QThread-Demo)
46
76
 
47
77
  ```python
48
78
 

2

QThread::requestInterruption を使ってスレッドを中断するサンプルを追加

2020/06/07 06:55

投稿

teamikl
teamikl

スコア8742

test CHANGED
@@ -36,12 +36,22 @@
36
36
 
37
37
 
38
38
 
39
-
39
+ 追記: repl.it 上にコードを載せました。
40
+
40
-
41
+ ソースコメント内の日本語は文字化けしますが、ブラウザ上で実行可能です。
42
+
43
+
44
+
41
-
45
+ https://repl.it/@MiKLTea/QThread-Demo
42
46
 
43
47
  ```python
44
48
 
49
+ #!/usr/bin/env python3.8
50
+
51
+
52
+
53
+ import logging
54
+
45
55
  from threading import Thread, current_thread
46
56
 
47
57
 
@@ -58,6 +68,10 @@
58
68
 
59
69
 
60
70
 
71
+ logger = logging.getLogger(__name__)
72
+
73
+
74
+
61
75
 
62
76
 
63
77
  class MainWindow(QWidget):
@@ -76,8 +90,6 @@
76
90
 
77
91
 
78
92
 
79
-
80
-
81
93
  def closeEvent(self, event):
82
94
 
83
95
  self.cancelThreadLoop()
@@ -104,12 +116,26 @@
104
116
 
105
117
  def cancelThreadLoop(self):
106
118
 
107
- print("cancel")
119
+ logger.debug("cancel")
120
+
121
+
122
+
123
+ # autoThreadPython, autoThreadQt の中断。
124
+
125
+ # TODO: このコードは Thread-Safe でないので、Mutexを使った方が良い。
108
126
 
109
127
  self.running = False
110
128
 
111
129
 
112
130
 
131
+ if self.qt_thread:
132
+
133
+ # autoInterruptionThreadQt の中断
134
+
135
+ self.qt_thread.requestInterruption()
136
+
137
+
138
+
113
139
  def initUI(self):
114
140
 
115
141
  label = self.label = QLabel("")
@@ -124,7 +150,7 @@
124
150
 
125
151
 
126
152
 
127
- items = ["autoThreadPython", "autoThreadQt"]
153
+ items = ["autoThreadPython", "autoThreadQt", "autoInterruptionThreadQt"]
128
154
 
129
155
  func = None
130
156
 
@@ -198,9 +224,7 @@
198
224
 
199
225
  def setCount(self, count):
200
226
 
201
- # 呼び出されたスレッドの確認
202
-
203
- # print("setCount", count, current_thread())
227
+ logger.debug("setCount {}".format(count))
204
228
 
205
229
  self.label.setText("Count: {}".format(count))
206
230
 
@@ -244,7 +268,7 @@
244
268
 
245
269
 
246
270
 
247
- print("Python Thread Finished")
271
+ logger.debug("Python Thread Finished")
248
272
 
249
273
 
250
274
 
@@ -294,7 +318,7 @@
294
318
 
295
319
  thread.sendCount.connect(self.setCount) # メインスレッド側で実行される
296
320
 
297
- thread.finished.connect(lambda: print("Qt Thread Finished"))
321
+ thread.finished.connect(lambda: logger.debug("Qt Thread Finished"))
298
322
 
299
323
  thread.start()
300
324
 
@@ -306,10 +330,64 @@
306
330
 
307
331
 
308
332
 
333
+ def autoInterruptionThreadQt(self):
334
+
335
+
336
+
337
+ win = self
338
+
339
+ win.running = True
340
+
341
+
342
+
343
+ class MyQtThreadEx(QThread):
344
+
345
+
346
+
347
+ sendCount = pyqtSignal(int)
348
+
349
+
350
+
351
+ def run(self):
352
+
353
+ for num in range(10):
354
+
355
+ # NOTE: QThread::requestInterruption() で中断要求
356
+
357
+ if self.isInterruptionRequested():
358
+
359
+ break
360
+
361
+ self.sendCount.emit(num)
362
+
363
+ self.sleep(1)
364
+
365
+
366
+
367
+ thread = self.qt_thread = MyQtThreadEx()
368
+
369
+ thread.sendCount.connect(self.setCount) # メインスレッド側で実行される
370
+
371
+ thread.finished.connect(lambda: logger.debug("Qt Thread Finished"))
372
+
373
+ thread.start()
374
+
375
+
376
+
377
+
378
+
309
379
  def main():
310
380
 
311
381
  import sys
312
382
 
383
+ logging.basicConfig(
384
+
385
+ level=logging.DEBUG,
386
+
387
+ format="[%(levelname)8s][%(threadName)-10s] %(message)s",
388
+
389
+ )
390
+
313
391
  app = QApplication(sys.argv)
314
392
 
315
393
  win = MainWindow()
@@ -330,6 +408,10 @@
330
408
 
331
409
  main()
332
410
 
411
+
412
+
413
+
414
+
333
415
  ```
334
416
 
335
417
 

1

スレッド確認のコードを追加(コメントアウト)

2020/06/07 06:41

投稿

teamikl
teamikl

スコア8742

test CHANGED
@@ -198,6 +198,10 @@
198
198
 
199
199
  def setCount(self, count):
200
200
 
201
+ # 呼び出されたスレッドの確認
202
+
203
+ # print("setCount", count, current_thread())
204
+
201
205
  self.label.setText("Count: {}".format(count))
202
206
 
203
207