(Python) Stop thread with raw input?
<p><strong>EDIT 9/15/16:</strong> In my original code (still posted below) I tried to use <code>.join()</code> with a function, which is a silly mistake because it can only be used with a thread object. I am trying to 
(1) continuously run a thread that gets data and saves it to a file 
(2) have a second thread, or incorporate queue, that will stop the program once a user enters a flag (i.e. "stop"). It doesn't interrupt the data gathering/saving thread. </p>

<p>I need help with multithreading. I am trying to run two threads, one that handles data and the second checks for a flag to stop the program.</p>

<p>I learned by trial and error that I can't interrupt a while loop without my computer exploding. Additionally, I have abandoned my GUI code because it made my code too complicated with the mulithreading.</p>

<p>What I want to do is run a thread that gathers data from an Arduino, saves it to a file, and repeats this. The second thread will scan for a <strong>flag</strong> -- which can be a raw_input? I can't think of anything else that a user can do to stop the data acquisition program. </p>

<p>I greatly appreciate any help on this. Here is my code (much of it is pseudocode, as you can see):</p>

<pre><code>#threading
import thread
import time

global flag

def monitorData():
    print "running!"
    time.sleep(5)

def stopdata(flag ):

    flag = raw_input("enter stop: ")

    if flag == "stop":
        monitorData.join()

flag = "start"

thread.start_new_thread( monitorData,())
thread.start_new_thread( stopdata,(flag,))
</code></pre>

<p>The error I am getting is this when I try entering "stop" in the IDLE. </p>

<p><em>Unhandled exception in thread started by 
Traceback (most recent call last):
  File "c:\users\otangu~1\appdata\local\temp\IDLE_rtmp_h_frd5", line 16, in stopdata
AttributeError: 'function' object has no attribute 'join'</em></p>

<p>Once again I really appreciate any help, I have taught myself Python so far and this is the first huge wall that I've hit. </p>

<p>The error you see is a result of calling join on the function. You need to call <code>join</code> on the <code>thread</code> object. You don't capture a reference to the thread so you have no way to call <code>join</code> anyway. You should <code>join</code> like so.</p>

<pre><code>th1 = thread.start_new_thread( monitorData,())

# later
th1.join()
</code></pre>

<p>As for a solution, you can use a <code>Queue</code> to communicate between threads. The queue is used to send a quit message to the worker thread and if the worker does not pick anything up off the queue for a second it runs the code that gathers data from the arduino.</p>

<pre><code>from threading import Thread
from Queue import Queue, Empty


def worker(q):
    while True:

        try:
            item = q.get(block=True, timeout=1)

            q.task_done()
            if item == "quit":
                print("got quit msg in thread")
                break

        except Empty:
            print("empty, do some arduino stuff")


def input_process(q):
    while True:
        x = raw_input("")

        if x == 'q':
            print("will quit")
            q.put("quit")
            break

q = Queue()
t = Thread(target=worker, args=(q,))
t.start()

t2 = Thread(target=input_process, args=(q,))
t2.start()

# waits for the `task_done` function to be called
q.join()

t2.join()
t.join()
</code></pre>

<p>It's possibly a bit more code than you hoped for and having to detect the queue is empty with an exception is a little ugly, but this doesn't rely on any global variables and will always exit promptly. That wont be the case with <code>sleep</code> based solutions, which need to wait for any current calls to <code>sleep</code> to finish before resuming execution.</p>

<p>As noted by someone else, you should really be using <code>threading</code> rather than the older <code>thread</code> module and also I would recommend you learn with python 3 and not python 2. </p>

python multithreading