Home > database >  Python Queue not pulling thread objects in order. Only working on last thread which never ends
Python Queue not pulling thread objects in order. Only working on last thread which never ends

Time:02-22

When running my code, the "Teller" threads help the same "Customer" thread over and over again until an undetermined amount of times. I don't understand why the last customer created gets helped over and over though the other threads were created.

I am unsure if a .join() is necessary somewhere in the code for the Customer threads. I have placed it in multiple places in the code and my code seems to get stuck.

from threading import Semaphore, Thread, Lock
from queue import Queue, Empty
from random import randint
from time import sleep

max_customers_in_bank = 10
'''maximum number of customers that can be in
the bank at one time'''
max_customers = 7  # number of customers that will go to the bank today
max_tellers = 2  # number of tellers working today
teller_timeout = 10  # longest time that a teller will wait for new customers


# Part I
class Customer:

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return {self.name}


class Teller:

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return {self.name}


def bankprint(lock, msg):
    # Print message with a context manager lock
    with lock:
        print(msg)


def wait_outside_bank(customer, guard, teller_line, printlock):
    # Call bankprint and format customer object string approiately for call
    bankprint(printlock, ("(C) '"   customer.name   "' waiting outside bank"))
    # Create semphore for max customers and aquire it
    guard.acquire()
    bankprint(printlock,
              ("<G> Security guard letting '"  
               customer.name   "' into the bank"))
    bankprint(printlock, ("(C) '"   customer.name   "' getting into line"))
    # Create teller line queue and put custiomers into queue
    teller_line.put(customer)
    
    


# Part III
def teller_job(teller, guard, teller_line, printlock):
    bankprint(printlock, ("[T] '"   teller.name   "' starting work"))
    while True:
        try:
            teller_line.get(timeout=teller_timeout)
            bankprint(printlock, ("[T] '"   teller.name   "' is now helping"  
                                  customer.name))
            sleep(randint(1, 4))
            bankprint(printlock, ("[T] '"   teller.name   "' is done helping"  
                                  customer.name))
            bankprint(printlock, ("<G> Security guard letting '"  
                                  customer.name   "' out of the bank"))
            guard.release()
        except Empty:
            bankprint(printlock, ("[T] Nobody is in line, '"   teller.name  
                                  "' is going on break"))
            break


if __name__ == "__main__":
    printlock = Lock()
    teller_line = Queue(maxsize=max_customers_in_bank)
    guard = Semaphore(max_customers_in_bank)
    Customer_List = [Customer("Customer_" str(i)) for i in
                     range(1, max_customers 1)]
    for customer in Customer_List:
        thread = Thread(target=wait_outside_bank,
                        args=(customer, guard, teller_line, printlock))
        thread.start()
    sleep(5)
    print("*B* Tellers starting work")
    Teller_List = [Teller("Teller_" str(i)) for i in range(1, max_tellers 1)]
    Teller_Threads = [Thread(target = teller_job, args = (teller, guard, teller_line, printlock)) for teller in Teller_List]
    for teller in Teller_Threads: 
        teller.start()

    for teller in Teller_Threads:
        teller.join()
    print("*B* Bank closed")

Sample Output:

(C) 'Customer_1' waiting outside bank
<G> Security guard letting 'Customer_1' into the bank
(C) 'Customer_1' getting into line
(C) 'Customer_2' waiting outside bank
(C) 'Customer_3' waiting outside bank
<G> Security guard letting 'Customer_2' into the bank
(C) 'Customer_4' waiting outside bank
<G> Security guard letting 'Customer_3' into the bank
(C) 'Customer_3' getting into line
(C) 'Customer_2' getting into line
(C) 'Customer_6' waiting outside bank
<G> Security guard letting 'Customer_4' into the bank
(C) 'Customer_4' getting into line
(C) 'Customer_7' waiting outside bank
<G> Security guard letting 'Customer_6' into the bank
(C) 'Customer_5' waiting outside bank
<G> Security guard letting 'Customer_7' into the bank
(C) 'Customer_7' getting into line
<G> Security guard letting 'Customer_5' into the bank
(C) 'Customer_5' getting into line
(C) 'Customer_6' getting into line
*B* Tellers starting work
[T] 'Teller_1' starting work
[T] 'Teller_1' is now helpingCustomer_7
[T] 'Teller_2' starting work
[T] 'Teller_2' is now helpingCustomer_7
[T] 'Teller_1' is done helpingCustomer_7
<G> Security guard letting 'Customer_7' out of the bank
[T] 'Teller_1' is now helpingCustomer_7
[T] 'Teller_2' is done helpingCustomer_7
<G> Security guard letting 'Customer_7' out of the bank
[T] 'Teller_2' is now helpingCustomer_7
[T] 'Teller_1' is done helpingCustomer_7
[T] 'Teller_2' is done helpingCustomer_7
<G> Security guard letting 'Customer_7' out of the bank
<G> Security guard letting 'Customer_7' out of the bank
[T] 'Teller_1' is now helpingCustomer_7
[T] 'Teller_2' is now helpingCustomer_7
[T] 'Teller_1' is done helpingCustomer_7
<G> Security guard letting 'Customer_7' out of the bank
[T] 'Teller_1' is now helpingCustomer_7
[T] 'Teller_2' is done helpingCustomer_7
<G> Security guard letting 'Customer_7' out of the bank
[T] 'Teller_1' is done helpingCustomer_7
<G> Security guard letting 'Customer_7' out of the bank
[T] Nobody is in line, 'Teller_2' is going on break
[T] Nobody is in line, 'Teller_1' is going on break
*B* Bank closed

CodePudding user response:

teller_job does not define customer so when you use customer.name, you use the customer in the global namespace. It was assigned in the for loop for customer in Customer_List: and that loop has finished (leaving the last customer in the list as it last value) before the threads do the processing.

  • Related