[Tutor] python gtk serial loop thread readind data close

Cameron Simpson cs at zip.com.au
Sat Apr 1 18:46:23 EDT 2017


On 30Mar2017 12:40, Alexandru Achim <achim_alexandru at yahoo.com> wrote:
>Dear users,
>I had a problem regarding Threads in python and Gtk3. I want to stop a while loop in Gtk , a loop starded with a thread.
>I want to control a delay timer laser board with give me ,when I send a command by serial connection, give back continuous status values ; but I want to stop this loop , to modify parameters and start the loop again.
>
>A part of my code is here :
>import serial
>import threading
>import gi
>gi.require_version('Gtk', '3.0')
>from gi.repository import Gtk
>from gi.repository import GObject,Pango, GLib
>from threading import Thread
>GObject.threads_init().............
>#START BUTTON
>
>    def start(self,button_start):
>       Thread(target=self.start_on,args=(self.button_start))

You don't seem to start the Thread here.

>    def start_on(self,widget,data=None):
>    if ser.isOpen():
>        cmd = 's'   
>        ser.write(cmd.encode('ascii')+'\r\n')
>        while True:
>            try:
>                 values = ser.readline()
>                 self.label_result.set_text(values)
>            except:
>                      pass
>       
>#STOP BUTTON        
>    def stop(self,button_stop):
>     Thread(target=self.stops,args=(button_stop)).start()
>       
>    def stops(self,widget,data=None):
>    if ser.isOpen():
>        try:  
>            cmd = 'f'   
>            ser.write(cmd.encode('ascii')+'\r\n')
>            status = ser.readline()
>            self.label_result.set_text(status)
>        except:
>            pass
>...........win=sincrolaser()
>win.show_all()
>Gtk.main()
>
>But the problem is when I send STOP button program freeze , probably the loop from the start is looping forever. How do I stop the start thread?
>Is there a posibility to give a thread flag or identity to find him and close?

It is easy enough to keep the identities of threads. Example:

  def start(self, button,start):
    self.start_thread = Thread(target=.......)
    self.start_thread.start()

But to stop a thread you pretty much need to set a flag and have the thread 
check it periodicly. Example:

  def start(self, button,start):
    self.start_thread = Thread(target=.......)
    self.start_run = True
    self.start_thread.start()

  def start_one(self, widget, data=None):
    ...
    while self.start_run:
      try:
        ...

and to stop it one goes:

  self.start_run = False

Next time around the loop the thread checks the flag and quits the while loop.

Another concern I have with your code is that nothing prevents _both_ the stop 
and start threads from running at the same time. I Imagine that calling 
ser.readline from two threads at once leads to unpredictable and possible 
insane behaviour. And having both threads writing to the serial line at one may 
write nonsense to the other end, etc.

I recommand you take a mutex around your worker threads, so that only one can 
be active at once. Example:

  from threading import Lock

  # wherever your setup stuff happens; you need to allocate the Lock
  def __init__(self, ...):
    self.ser_lock = Lock()

  def start_one(self, widget, data=None):
    with self.ser_lock:
      ...
      while start_run:
        try:
          ..

and likewise in stops:

  def stop(self,button_stop):
    self.start_run = False    # ask "start" tyhread to terminate
    self.stop_thread = Thread(target=self.stops,args=(button_stop))
    self.stop_thread.start()

  def stops(self,widget,data=None):
    with self.ser_lock:
      if ser.isOpen():
        try:  
          ...

You can see that neither thread will try to user the serial device until it 
holds the lock, avoiding conflict. The stop button active sets the "start_run" 
flag variable to False, causing the start thread to exit when it notices.

Hopefully this will give you more control over your program's behaviour. A few 
helpful print() calls scattered throughout should show you what is going on, 
too.

Note that it would also be prudent to prevent more than one start thread 
running, and so forth.

Cheers,
Cameron Simpson <cs at zip.com.au>


More information about the Tutor mailing list