multithreading - Reading and writing from a single serial port simultaneously from multiple threads -
i have serial port gives me lot of different data different pieces of hardware. need send different commands serial port receive different kinds of data it. so, need write , read data simultaneously port in different functions. sometimes, might need read , write simultaneously serial port in 10 different threads. best way of writing code in situation simultaneously reading/writing data single port? threads, sub processes, etc.
start straightforward code works in case. if script starts multiple threads add reader/writer threads communicate controller -- other threads send/receive data these threads: send_queue
consumed writer thread used send commands controller , each worker thread has own receive_queue
populated reader thread:
#!/usr/bin/env python2 """communicate dummy controller 10 worker threads. - start controller subprocess, worker threads - send requests , check responses in worker threads concurrently - wait until responses received """ import json import logging import sys queue import queue subprocess import popen, pipe threading import thread log = logging.getlogger(__name__).debug def worker(tid, send_queue, receive_queue): """send dummy requests, responses.""" log('starting worker tid=%s', tid) in range(5): log('sending request key=%s, data=%d', tid, i) send_queue.put(dict(key=tid, data=i)) # send request response = receive_queue.get() # response # check response log('got response %s, key=%s, data=%d', response, tid, i) assert response['key'] == tid , response['data'] == i**2 def reader(pipe, thread_queues): """read responses controller (*pipe*). dispatch them corresponding threads. """ log('starting reader') pipe: line in iter(pipe.readline, b''): # read response controller log('got line %r', line) response = json.loads(line) # dispatch corresponding thread thread_queues[response['key']].put(response) def writer(pipe, send_queue): """write requests controller (*pipe*) *send_queue*.""" log('starting writer') pipe: request in iter(send_queue.get, none): log('sending request %s', request) print >>pipe, json.dumps(request) def start_daemon_thread(*args, **kwargs): """start , return daemonic thread.""" t = thread(*args, **kwargs) t.daemon = true # die program t.start() return t def main(): nthreads = 10 timeout = 1 # seconds, ctrl+c logging.basicconfig(format="%(asctime)-15s %(threadname)s %(message)s", datefmt='%f %t', level=logging.debug) # start controller controller = popen([sys.executable, "-u", "dummy_controller.py"], stdin=pipe, stdout=pipe, bufsize=1) # start threads send_queue = queue(maxsize=50) # limit number of queued requests (backlog) thread_queues = {tid: queue() tid in range(1, nthreads + 1)} threads = [start_daemon_thread(name='worker-' + str(tid), target=worker, args=[tid, send_queue, q]) tid, q in thread_queues.items()] # read/write until there requests start_daemon_thread(name='writer', target=writer, args=[controller.stdin, send_queue]) log('about start reader') reader_thread = start_daemon_thread(name='reader', target=reader, args=[controller.stdout, thread_queues]) # wait until workers done while threads: t in threads: t.join(timeout) # workaround, enable ctrl+c on python 2.7 if not t.is_alive(): threads.remove(t) break log('no worker threads') send_queue.put(none) # no more requests # wait until responses received while reader_thread.is_alive(): reader_thread.join(timeout) # workaround, enable ctrl+c on python 2.7 controller.wait() # wait subprocess exit (to avoid zombies) log('done') if __name__ == "__main__": main()
where dummy_controller.py
simple script computes x**2
each input x
:
#!/usr/bin/env python2 """dummy controller.""" import json import sys line in iter(sys.stdin.readline, b''): request = json.loads(line) # square data field in request , send print json.dumps(dict(request, data=int(request['data'])**2))
your code don't need subprocess, should call appropriate read/write methods serial port instead of starting subprocess , using pipes.
the code verbose , not optimized speed. if worker threads cpu-bound should find way release gil (e.g., on cpython implementation): c extensions or offload work process pool; otherwise 1 cpu core used python implementation gil (cpython, pypy (default)).
example output
2015-09-27 20:02:38 worker-1 starting worker tid=1 2015-09-27 20:02:38 worker-1 sending request key=1, data=0 2015-09-27 20:02:38 worker-2 starting worker tid=2 2015-09-27 20:02:38 worker-3 starting worker tid=3 2015-09-27 20:02:38 worker-3 sending request key=3, data=0 2015-09-27 20:02:38 worker-2 sending request key=2, data=0 2015-09-27 20:02:38 worker-5 starting worker tid=5 2015-09-27 20:02:38 worker-4 starting worker tid=4 2015-09-27 20:02:38 worker-6 starting worker tid=6 2015-09-27 20:02:38 worker-7 starting worker tid=7 2015-09-27 20:02:38 worker-5 sending request key=5, data=0 2015-09-27 20:02:38 worker-6 sending request key=6, data=0 2015-09-27 20:02:38 worker-4 sending request key=4, data=0 2015-09-27 20:02:38 worker-8 starting worker tid=8 2015-09-27 20:02:38 worker-7 sending request key=7, data=0 2015-09-27 20:02:38 worker-9 starting worker tid=9 2015-09-27 20:02:38 worker-8 sending request key=8, data=0 2015-09-27 20:02:38 worker-9 sending request key=9, data=0 2015-09-27 20:02:38 worker-10 starting worker tid=10 2015-09-27 20:02:38 worker-10 sending request key=10, data=0 2015-09-27 20:02:38 mainthread start reader 2015-09-27 20:02:38 writer starting writer 2015-09-27 20:02:38 reader starting reader 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 1} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 3} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 2} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 5} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 6} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 4} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 7} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 8} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 9} 2015-09-27 20:02:38 writer sending request {'data': 0, 'key': 10} 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 1}\n' 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 3}\n' 2015-09-27 20:02:38 worker-1 got response {u'data': 0, u'key': 1}, key=1, data=0 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 2}\n' 2015-09-27 20:02:38 worker-3 got response {u'data': 0, u'key': 3}, key=3, data=0 2015-09-27 20:02:38 worker-1 sending request key=1, data=1 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 5}\n' 2015-09-27 20:02:38 worker-2 got response {u'data': 0, u'key': 2}, key=2, data=0 2015-09-27 20:02:38 worker-3 sending request key=3, data=1 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 1} 2015-09-27 20:02:38 worker-5 got response {u'data': 0, u'key': 5}, key=5, data=0 2015-09-27 20:02:38 worker-2 sending request key=2, data=1 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 6}\n' 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 3} 2015-09-27 20:02:38 worker-5 sending request key=5, data=1 2015-09-27 20:02:38 worker-6 got response {u'data': 0, u'key': 6}, key=6, data=0 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 4}\n' 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 2} 2015-09-27 20:02:38 worker-6 sending request key=6, data=1 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 7}\n' 2015-09-27 20:02:38 worker-4 got response {u'data': 0, u'key': 4}, key=4, data=0 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 5} 2015-09-27 20:02:38 worker-4 sending request key=4, data=1 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 8}\n' 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 6} 2015-09-27 20:02:38 worker-7 got response {u'data': 0, u'key': 7}, key=7, data=0 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 9}\n' 2015-09-27 20:02:38 worker-8 got response {u'data': 0, u'key': 8}, key=8, data=0 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 4} 2015-09-27 20:02:38 worker-7 sending request key=7, data=1 2015-09-27 20:02:38 reader got line '{"data": 0, "key": 10}\n' 2015-09-27 20:02:38 worker-9 got response {u'data': 0, u'key': 9}, key=9, data=0 2015-09-27 20:02:38 worker-8 sending request key=8, data=1 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 1}\n' 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 7} 2015-09-27 20:02:38 worker-10 got response {u'data': 0, u'key': 10}, key=10, data=0 2015-09-27 20:02:38 worker-9 sending request key=9, data=1 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 3}\n' 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 8} 2015-09-27 20:02:38 worker-1 got response {u'data': 1, u'key': 1}, key=1, data=1 2015-09-27 20:02:38 worker-10 sending request key=10, data=1 2015-09-27 20:02:38 worker-3 got response {u'data': 1, u'key': 3}, key=3, data=1 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 2}\n' 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 9} 2015-09-27 20:02:38 worker-1 sending request key=1, data=2 2015-09-27 20:02:38 worker-3 sending request key=3, data=2 2015-09-27 20:02:38 worker-2 got response {u'data': 1, u'key': 2}, key=2, data=1 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 5}\n' 2015-09-27 20:02:38 writer sending request {'data': 1, 'key': 10} 2015-09-27 20:02:38 worker-2 sending request key=2, data=2 2015-09-27 20:02:38 worker-5 got response {u'data': 1, u'key': 5}, key=5, data=1 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 6}\n' 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 1} 2015-09-27 20:02:38 worker-5 sending request key=5, data=2 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 4}\n' 2015-09-27 20:02:38 worker-6 got response {u'data': 1, u'key': 6}, key=6, data=1 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 3} 2015-09-27 20:02:38 worker-4 got response {u'data': 1, u'key': 4}, key=4, data=1 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 7}\n' 2015-09-27 20:02:38 worker-6 sending request key=6, data=2 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 2} 2015-09-27 20:02:38 worker-4 sending request key=4, data=2 2015-09-27 20:02:38 worker-7 got response {u'data': 1, u'key': 7}, key=7, data=1 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 8}\n' 2015-09-27 20:02:38 worker-7 sending request key=7, data=2 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 5} 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 9}\n' 2015-09-27 20:02:38 worker-8 got response {u'data': 1, u'key': 8}, key=8, data=1 2015-09-27 20:02:38 reader got line '{"data": 1, "key": 10}\n' 2015-09-27 20:02:38 worker-8 sending request key=8, data=2 2015-09-27 20:02:38 worker-9 got response {u'data': 1, u'key': 9}, key=9, data=1 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 6} 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 1}\n' 2015-09-27 20:02:38 worker-10 got response {u'data': 1, u'key': 10}, key=10, data=1 2015-09-27 20:02:38 worker-9 sending request key=9, data=2 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 4} 2015-09-27 20:02:38 worker-1 got response {u'data': 4, u'key': 1}, key=1, data=2 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 3}\n' 2015-09-27 20:02:38 worker-10 sending request key=10, data=2 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 7} 2015-09-27 20:02:38 worker-1 sending request key=1, data=3 2015-09-27 20:02:38 worker-3 got response {u'data': 4, u'key': 3}, key=3, data=2 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 2}\n' 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 8} 2015-09-27 20:02:38 worker-3 sending request key=3, data=3 2015-09-27 20:02:38 worker-2 got response {u'data': 4, u'key': 2}, key=2, data=2 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 5}\n' 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 9} 2015-09-27 20:02:38 worker-2 sending request key=2, data=3 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 6}\n' 2015-09-27 20:02:38 writer sending request {'data': 2, 'key': 10} 2015-09-27 20:02:38 worker-5 got response {u'data': 4, u'key': 5}, key=5, data=2 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 4}\n' 2015-09-27 20:02:38 worker-6 got response {u'data': 4, u'key': 6}, key=6, data=2 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 1} 2015-09-27 20:02:38 worker-5 sending request key=5, data=3 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 7}\n' 2015-09-27 20:02:38 worker-4 got response {u'data': 4, u'key': 4}, key=4, data=2 2015-09-27 20:02:38 worker-6 sending request key=6, data=3 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 3} 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 8}\n' 2015-09-27 20:02:38 worker-7 got response {u'data': 4, u'key': 7}, key=7, data=2 2015-09-27 20:02:38 worker-4 sending request key=4, data=3 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 2} 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 9}\n' 2015-09-27 20:02:38 worker-7 sending request key=7, data=3 2015-09-27 20:02:38 worker-8 got response {u'data': 4, u'key': 8}, key=8, data=2 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 5} 2015-09-27 20:02:38 worker-9 got response {u'data': 4, u'key': 9}, key=9, data=2 2015-09-27 20:02:38 reader got line '{"data": 4, "key": 10}\n' 2015-09-27 20:02:38 worker-8 sending request key=8, data=3 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 6} 2015-09-27 20:02:38 worker-9 sending request key=9, data=3 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 1}\n' 2015-09-27 20:02:38 worker-10 got response {u'data': 4, u'key': 10}, key=10, data=2 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 4} 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 3}\n' 2015-09-27 20:02:38 worker-10 sending request key=10, data=3 2015-09-27 20:02:38 worker-1 got response {u'data': 9, u'key': 1}, key=1, data=3 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 7} 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 2}\n' 2015-09-27 20:02:38 worker-3 got response {u'data': 9, u'key': 3}, key=3, data=3 2015-09-27 20:02:38 worker-3 sending request key=3, data=4 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 8} 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 5}\n' 2015-09-27 20:02:38 worker-2 got response {u'data': 9, u'key': 2}, key=2, data=3 2015-09-27 20:02:38 worker-2 sending request key=2, data=4 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 9} 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 6}\n' 2015-09-27 20:02:38 worker-5 got response {u'data': 9, u'key': 5}, key=5, data=3 2015-09-27 20:02:38 worker-1 sending request key=1, data=4 2015-09-27 20:02:38 writer sending request {'data': 3, 'key': 10} 2015-09-27 20:02:38 worker-6 got response {u'data': 9, u'key': 6}, key=6, data=3 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 4}\n' 2015-09-27 20:02:38 worker-5 sending request key=5, data=4 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 3} 2015-09-27 20:02:38 worker-6 sending request key=6, data=4 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 7}\n' 2015-09-27 20:02:38 worker-4 got response {u'data': 9, u'key': 4}, key=4, data=3 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 2} 2015-09-27 20:02:38 worker-7 got response {u'data': 9, u'key': 7}, key=7, data=3 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 8}\n' 2015-09-27 20:02:38 worker-4 sending request key=4, data=4 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 1} 2015-09-27 20:02:38 worker-7 sending request key=7, data=4 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 9}\n' 2015-09-27 20:02:38 worker-8 got response {u'data': 9, u'key': 8}, key=8, data=3 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 5} 2015-09-27 20:02:38 reader got line '{"data": 9, "key": 10}\n' 2015-09-27 20:02:38 worker-9 got response {u'data': 9, u'key': 9}, key=9, data=3 2015-09-27 20:02:38 worker-8 sending request key=8, data=4 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 6} 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 3}\n' 2015-09-27 20:02:38 worker-10 got response {u'data': 9, u'key': 10}, key=10, data=3 2015-09-27 20:02:38 worker-9 sending request key=9, data=4 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 4} 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 2}\n' 2015-09-27 20:02:38 worker-3 got response {u'data': 16, u'key': 3}, key=3, data=4 2015-09-27 20:02:38 worker-10 sending request key=10, data=4 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 7} 2015-09-27 20:02:38 worker-2 got response {u'data': 16, u'key': 2}, key=2, data=4 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 1}\n' 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 8} 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 5}\n' 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 9} 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 6}\n' 2015-09-27 20:02:38 worker-5 got response {u'data': 16, u'key': 5}, key=5, data=4 2015-09-27 20:02:38 worker-1 got response {u'data': 16, u'key': 1}, key=1, data=4 2015-09-27 20:02:38 writer sending request {'data': 4, 'key': 10} 2015-09-27 20:02:38 worker-6 got response {u'data': 16, u'key': 6}, key=6, data=4 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 4}\n' 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 7}\n' 2015-09-27 20:02:38 worker-4 got response {u'data': 16, u'key': 4}, key=4, data=4 2015-09-27 20:02:38 worker-7 got response {u'data': 16, u'key': 7}, key=7, data=4 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 8}\n' 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 9}\n' 2015-09-27 20:02:38 worker-8 got response {u'data': 16, u'key': 8}, key=8, data=4 2015-09-27 20:02:38 reader got line '{"data": 16, "key": 10}\n' 2015-09-27 20:02:38 worker-9 got response {u'data': 16, u'key': 9}, key=9, data=4 2015-09-27 20:02:38 worker-10 got response {u'data': 16, u'key': 10}, key=10, data=4 2015-09-27 20:02:38 mainthread no worker threads 2015-09-27 20:02:38 mainthread done
Comments
Post a Comment