leon
leon

Reputation: 29

Command line multithreading

I am writing a simple command-line program that shows the current time and let user set the alarm. However, the alarm did not ring as the raw_input was blocking it. I have even implement multithreading but it didn't work as well. Here's the full code:

import datetime, time, thread, os

program_running = True
now = datetime.datetime.now()
alarm_status = 0
alarm_hour = 0
alarm_minute = 0

def clock():
    now = datetime.datetime.now()
    print now.strftime('%H:%M')

def set_alarm():    
    global alarm_hour, alarm_minute, alarm_status

    alarm_time = raw_input('Set Alarm (XX:XX) : ')    
    alarm_hour = alarm_time[:alarm_time.find(':')]
    alarm_minute = alarm_time[alarm_time.find(':')+1:]
    alarm_status = 1 

def alert_thread():
    global alarm_hour, alarm_minute, alarm_status 
    while True:
        if(alarm_status):
                if (str(now.hour) == str(alarm_hour) and str(now.minute) == str(alarm_minute)):
                    print 'Ring.. Ring..'
                    alarm_status = 0

#program start here
thread.start_new_thread(alert_thread,())
while(program_running):
    now = datetime.datetime.now()


    print '1) Clock'
    print '2) Alarm'
    print '3) Quit'
    choice = input('Choose (1-6) : ')

    if(choice==1):
        clock()
    elif(choice==2):
        set_alarm()
    elif(choice==3):
        program_running = False

Upvotes: 0

Views: 3563

Answers (3)

jfs
jfs

Reputation: 414235

raw_input() doesn't prevent other threads to print. Here's a small example:

from threading import Timer

def ring():
    print "\nRing.. Ring.."

t = Timer(3, ring) # ring in 3 seconds
t.start()
s = raw_input("wait for the ring, press enter afterwards")

Output:

wait for the ring, press enter afterwards..
Ring.. Ring..

Upvotes: 0

spicavigo
spicavigo

Reputation: 4224

2 Things

  1. In the while loop of thread, put a sleep
  2. Just before the inner if of thread, do

    now = datetime.datetime.now()

Upvotes: 0

pypat
pypat

Reputation: 1116

I find the implementation with globals and only a single thread for alarms a little strange. This way you can always only have set one alarm at a time and there will always be an alarm thread running even without any alarm being set. Also your now is never being updated to the alarm shouldn't run at all. Maybe consider doing it like this. This isjust a quick refactor, not saying this is perfect but it should help you get on:

import datetime, time, threading, os


def clock():
    now = datetime.datetime.now()
    print now.strftime('%H:%M')

def set_alarm():    
    alarm_time = raw_input('Set Alarm (XX:XX) : ')    
    alarm_hour = alarm_time[:alarm_time.find(':')]
    alarm_minute = alarm_time[alarm_time.find(':')+1:]
    alarm_thread = threading.Thread(target=alert_thread, args=(alarm_time, alarm_hour, alarm_minute))
    alarm_thread.start()

def alert_thread(alarm_time, alarm_hour, alarm_minute):
    print "Ringing at {}:{}".format(alarm_hour, alarm_minute)
    while True:
        now = datetime.datetime.now()
        if str(now.hour) == str(alarm_hour) and str(now.minute) == str(alarm_minute):
            print ("Ring.. Ring..")
            break


#program start here
while True:
    now = datetime.datetime.now()
    print '1) Clock'
    print '2) Alarm'
    print '3) Quit'
    choice = input('Choose (1-6) : ')

    if(choice==1):
        clock()
    elif(choice==2):
        set_alarm()
    elif(choice==3):
        break

Upvotes: 1

Related Questions