get rid of thread killing

Switching to a cooperative model.  This has the downside that a long
patch computation will cause the simulate window to take longer to
update, but in practice the longest this will be is a couple of
seconds (for a very complicated autofill region).
pull/10/head
Lex Neva 2017-12-30 21:15:34 -05:00
rodzic 7152caa14d
commit cb6df39773
1 zmienionych plików z 17 dodań i 41 usunięć

Wyświetl plik

@ -6,7 +6,7 @@ import sys
import json
import traceback
import time
from threading import Thread
from threading import Thread, Event
from copy import copy
from cStringIO import StringIO
import wx
@ -18,40 +18,6 @@ from functools import partial
from itertools import groupby
from embroider_simulate import EmbroiderySimulator
class KillableThread(Thread):
"""A subclass of threading.Thread, with a kill() method."""
def __init__(self, *args, **keywords):
Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
"""Start the thread."""
self.__run_backup = self.run
self.run = self.__run # Force the Thread to install our trace.
Thread.start(self)
def __run(self):
"""Hacked run function, which installs the trace."""
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, why, arg):
if why == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, why, arg):
if self.killed:
if why == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
self.killed = True
def presets_path():
try:
import appdirs
@ -365,7 +331,7 @@ class SettingsFrame(wx.Frame):
self.simulate_window = None
self.simulate_thread = None
self.thread_num = 0
self.simulate_refresh_needed = Event()
self.presets_box = wx.StaticBox(self, wx.ID_ANY, label="Presets")
@ -402,12 +368,18 @@ class SettingsFrame(wx.Frame):
self.simulate_window.stop()
self.simulate_window.clear()
if self.simulate_thread and self.simulate_thread.is_alive():
self.simulate_thread.kill()
if not self.simulate_thread or not self.simulate_thread.is_alive():
self.simulate_thread = Thread(target=self.simulate_worker)
self.simulate_thread.daemon = True
self.simulate_thread.start()
self.simulate_thread = KillableThread(target=self.update_patches, name="Simulate%d" % self.thread_num)
self.simulate_thread.start()
self.thread_num += 1
self.simulate_refresh_needed.set()
def simulate_worker(self):
while True:
self.simulate_refresh_needed.wait()
self.simulate_refresh_needed.clear()
self.update_patches()
def update_patches(self):
patches = self.generate_patches()
@ -448,6 +420,10 @@ class SettingsFrame(wx.Frame):
try:
if tab.enabled() and not tab.is_dependent_tab():
for node in tab.nodes:
if self.simulate_refresh_needed.is_set():
# cancel, we need to start over
return []
# Making a copy of the embroidery element is an easy
# way to drop the cache in the @cache decorators used
# for many params in embroider.py.