回答編集履歴
4
説明文の修正
test
CHANGED
@@ -64,7 +64,7 @@
|
|
64
64
|
|
65
65
|
QThread を使う方法では、
|
66
66
|
|
67
|
-
メインスレッドのイベントループ
|
67
|
+
メインスレッドのイベントループが順番に処理する為、
|
68
68
|
|
69
69
|
同時アクセスは発生せずロックは不要です。(シグナル&スロットとイベントループを利用する恩恵)
|
70
70
|
|
3
リンクの修正と説明の追記(サンプルコードのロギングでスレッド名を表示)
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 を使ってスレッドを中断するサンプルを追加
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
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
スレッド確認のコードを追加(コメントアウト)
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
|
|