Using Timers and Threads in Python to create assis

2019-09-01 14:39发布

问题:

Let me describe my scenario:

I am developing a command line-based proof-of-concept for the instructional system, and I am writing it in Python. System works on the principles of behavioral psychology. I am rewarding users (children with special needs) for correct answers, and I am giving them correcting consequences for the wrong answers. I am also needing to provide hints to answers if they are struggling with answers.

Here is a high level pseudo code for my application:

Trial:

  1. Ask question such as 'What color is grass?'
  2. wait for answer
    a. If answer not provided within n seconds issue helping hint (e.g. "Gr, Gree")
    b. If answer is not provided within n+m seconds issue a corrective consequence. (e.g.,"Color of the grass is green.Let's try it again. ") and repeat the process
    c. If correct answer is provided during any n or n+m time praise the student and repeat the process.
    d. If the incorrect answer is provided during any of the n+m time, issue a corrective consequence and repeat the trial.

  3. Conclude the trial

So here is my observation and a dilemma:

Once I issue a question to student, I am waiting for events to happen on their own, or for my waiting to time out. I am also supposed to issue a hint during the wait period.

So far, in my main flow I used two threading.Timer objects, one to issue hint after n seconds and another one to issue corrective consequence if the answer never happens during the n+m period.

If answer happens of any kind during n or n+m time, I cancel the timers.

My question, however, is related to the main process. I also want to cancel the waiting on the answer if the answer waiting time-out happen. Just as I cancel timers, I also want to cancel waiting on the command line for the input if my final no-answer timeout occurs.

I am thinking to have one threading.Thread (get_answer) and two Timers (provide_hint, timeout_wait).

Thread get_answer is waiting on a response from a command line.

First timer (provide_hint) is giving a hint to user if there is no answer after n seconds.

Second timer (timeout_wait) is canceling out the thread (get_answer) if no answer happens after some period of n+m seconds.

Thread get_answer can cancel both timers if the answer happens be it correct or incorrect.

Questions I have here are:

A) Are my concurrent data structures correctly used and do you have any other suggestions?

B) Are there any possible deadlock issues and how to avoid them?

Thanks in advance.

回答1:

Here is a solution without using threads. It was tested on Linux, but probably works everywhere (but I'm unsure about Windows). It arranges for a SIGALRM signal to be delivered.

import signal

class Alarm(Exception):
    pass
def stop_me(*args):
    raise Alarm
signal.signal(signal.SIGALRM, stop_me)

def raw_input_with_timeout(timeout):
    try:
        signal.alarm(timeout)  # number in seconds
        try:
            return raw_input()
        finally:
            signal.alarm(0)   # stop the alarm
    except Alarm:
        return "alarm!"   # or anything

It's not a final solution because there are issues: if the user already typed part of a line, a SIGALRM will interrupt it, but what he typed so far remains in the read buffer of the terminal. It will be part of what the next raw_input() returns. You may have to turn the terminal in raw mode to avoid that. See Confusion about raw vs. cooked terminal modes? .