stoppable_thread.py 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. # Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import threading
  15. try:
  16. from typing import Optional
  17. except ImportError:
  18. pass
  19. class StoppableThread(object):
  20. """
  21. Provide a Thread-like class which can be 'cancelled' via a subclass-provided
  22. cancellation method.
  23. Can be started and stopped multiple times.
  24. Isn't an instance of type Thread because Python Thread objects can only be run once
  25. """
  26. def __init__(self):
  27. # type: () -> None
  28. self._thread = None # type: Optional[threading.Thread]
  29. @property
  30. def alive(self):
  31. # type: () -> bool
  32. """
  33. Is 'alive' whenever the internal thread object exists
  34. """
  35. return self._thread is not None
  36. def start(self):
  37. # type: () -> None
  38. if self._thread is None:
  39. self._thread = threading.Thread(target=self._run_outer)
  40. self._thread.start()
  41. def _cancel(self):
  42. # type: () -> None
  43. pass # override to provide cancellation functionality
  44. def run(self):
  45. # type: () -> None
  46. pass # override for the main thread behaviour
  47. def _run_outer(self):
  48. # type: () -> None
  49. try:
  50. self.run()
  51. finally:
  52. self._thread = None
  53. def stop(self):
  54. # type: () -> None
  55. if self._thread is not None:
  56. old_thread = self._thread
  57. self._thread = None
  58. self._cancel()
  59. old_thread.join()