0

I am trying to make an attendance system and right now, I want to create a random password, and put it on a countdown so that as it runs out, the student can't use the code anymore. However, when I try to run it, it only displays the password and the countdown, and only asks for input after the timer runs out.

I have attempted to use a for loop as well as the multiprocessing module to no avail. I suspect that the error is located somewhere around my use of the threads.

import threading

#create code and timer
Thread1 = threading.Thread(target=generateCodeandTimer(600))

# make input
Thread2 = threading.Thread(target=attend)

# Start the thread
Thread1.start()

# Start the thread
Thread2.start()

But for reference, this is my full code:

import string 
import random
import time
import sys
import threading

code = ""

def generateCodeandTimer(s):
    global code
    code = ''.join((random.choice(string.ascii_lowercase + string.digits) for x in range(6))) 
    print("Attendance code:", code) 
    
    while s != -1:
        mins = s // 60
        secs = s % 60
        countdown = '{:02d}:{:02d}'.format(mins, secs)
        sys.stdout.write('\r' + countdown)
        time.sleep(1)
        s -= 1

    if s==-1:
        print()
        print("Code expired")
    
    
def attend():
    print()
    studentinput = input("Please enter the code")
    if studentinput == code:
        print()
        print("Your attendance has been taken")
    else:
        print()
        print("Wrong code!")

#create code and timer
Thread1 = threading.Thread(target=generateCodeandTimer(600))

# make input
Thread2 = threading.Thread(target=attend)

# Start the thread
Thread1.start()

# Start the thread
Thread2.start()
2
  • Be aware of the global interpreter lock in Python. Consider coding in continuation-passing style Commented Jun 25, 2022 at 7:29
  • @BasileStarynkevitch The problem here has nothing to do with the GIL - not even close. Please try to be more careful when helping a new contributor. Commented Jun 27, 2022 at 6:45

1 Answer 1

1

In this line:

 Thread1 = threading.Thread(target=generateCodeandTimer(600))

you are actually calling the function generateCodeandTimer. The target keyword requires a function object, but this code calls the function and then passes the result as the target of the thread.

The second time you started a thread, you got it right:

Thread2 = threading.Thread(target=attend) 

Note the difference: target=attend passes the function object attend because you do not CALL the function. If you had written target=attend(), you would have called the function and passed its result as the target.

The solution is found in the documentation for the Thread constructor. Change the first thread creation to this:

Thread1 = threading.Thread(target=generateCodeandTimer, args=(600,))

The comma after 600 is necessary because the args= keyword requires a tuple.

Your program will now run as you intend. You will discover some other problems - for example, the program won't exit immediately when the user types in the password. But I will let you figure those out, or ask more questions if you run into trouble.

Sign up to request clarification or add additional context in comments.

2 Comments

Now I am running into problems with the threading, where the threads are taking turns in executing their tasks. causing a problem with the timer?
Threads take turns, yes, That's how they work. Your timer won't be accurate because you sleep for 1 second and don't take into account the time used by other threads, or the other code in the timer function itself. Since the only purpose of the timer is to expire eventually, is it important if it's not accurate? You can use the returned value from the function time.time() to correct it if you want to.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.