Wednesday 15 January 2014

python - Possible Race Condition in Serial read/write Code -



python - Possible Race Condition in Serial read/write Code -

i writing python code reads , writes serial device. device arduino mega running marlin 3d printer firmware.

my python code sending series of gcode commands (ascii strings terminated newlines, including checksums , line numbers). marlin responds each received line "ok\n". marlin has limited line buffer size if total marlin hold off on sending "ok\n" response until space freed up.

if checksum fails marlin requests line sent 1 time again "resend: 143\n" response. possible response "ok t:{temp value}\n" if current temperature requested.

my code uses 3 threads. main thread, read thread , write thread. here stripped downwards version of code:

class printer: def connect(self): self.s = serial.serial(self.port, self.baudrate, timeout=3) self.ok_received.set() def _start_print_thread(self): self.print_thread = thread(target=self._empty_buffer, name='print') self.print_thread.setdaemon(true) self.print_thread.start() def _start_read_thread(self): self.read_thread = thread(target=self._continous_read, name='read') self.read_thread.setdaemon(true) self.read_thread.start() def _empty_buffer(self): while not self.stop_printing: if self.current_line_idx < len(self.buffer): while not self.ok_received.is_set() , not self.stop_printing: logger.debug('waiting on ok_received') self.ok_received.wait(2) line = self._next_line() self.s.write(line) self.current_line_idx += 1 self.ok_received.clear() else: break def _continous_read(self): while not self.stop_reading: if self.s not none: line = self.s.readline() if line == 'ok\n': self.ok_received.set() go on # if got ok need nil else. if 'resend:' in line: # illustration line: "resend: 143" self.current_line_idx = int(line.split()[1]) - 1 if line: # if received _anything_ set flag self.ok_received.set() else: # if no printer attached, wait 10ms check again. sleep(0.01)

in above code, self.ok_received threading.event. mostly works ok. 1 time every couple of hours gets stuck in while not self.ok_received.is_set() , not self.stop_printing: loop within of _empty_buffer(). kills print locking machine.

when stuck within loop, can print go on sending command manually. allows read thread set ok_recieved flag.

since marlin not respond checksums, guess possible "ok\n" gets garbled. 3rd if statement in read thread supposed handle setting flag if anything received marlin.

so question is: have possible race status somewhere? before add together locks on place or combine 2 threads 1 understand how failing. advice appreciated.

it looks read thread info in window write thread has broken out of is_set loop, has not yet called self.ok_received.clear(). so, read thread ends calling self.ok_received.set() while write thread still processing previous line, , write thread unknowingly calls clear() 1 time done processing previous message, , never knows line should written.

def _empty_buffer(self): while not self.stop_printing: if self.current_line_idx < len(self.buffer): while not self.ok_received.is_set() , not self.stop_printing: logger.debug('waiting on ok_received') self.ok_received.wait(2) # start of race window line = self._next_line() self.s.write(line) self.current_line_idx += 1 # end of race window self.ok_received.clear() else: break

a queue might way handle - want write 1 line in write thread every time read thread receives line. if replaced self.ok_received.set() self.recv_queue.put("line"), write thread write 1 line every time pulls queue:

def _empty_buffer(self): while not self.stop_printing: if self.current_line_idx < len(self.buffer): while not self.stop_printing: logger.debug('waiting on ok_received') try: val = self.recv_queue.get(timeout=2) except queue.empty: pass else: break line = self._next_line() self.s.write(line) self.current_line_idx += 1 else: break

you shrink window point won't nail in practice moving phone call self.ok_received.clear() after exiting inner while loop, technically there still race.

python multithreading serial-port python-multithreading

No comments:

Post a Comment