summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLex Neva <github.com@lexneva.name>2017-12-30 21:15:34 -0500
committerLex Neva <github.com@lexneva.name>2017-12-30 21:16:58 -0500
commitcb6df397738c3a926a55c6d2e96c32787c46f4c4 (patch)
treeb70d7bb9ded20fc1407a0a33416953b91a3f5aff
parent7152caa14d9c0ec912b5326fde58c0c410e45391 (diff)
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).
-rw-r--r--embroider_params.py58
1 files changed, 17 insertions, 41 deletions
diff --git a/embroider_params.py b/embroider_params.py
index 58feafcb..fc472d36 100644
--- a/embroider_params.py
+++ b/embroider_params.py
@@ -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.