1
votes

I'm writing an emulator for a vintage computer system in Python, and I'm having some trouble with an exception thrown when trying to "restart" the emulator core thread after coming out of a halt condition. The "run processor" method, part of a larger class looks something like this:

def run_processor(self):
    processor = self

    class processor_thread(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
            self.daemon = True

        def run(self):
            while processor.running:
               #main loop for instruction fetch and decode is here   

    self.processor_thread = processor_thread()
    self.running = True   
    self.processor_thread.start()

I have a main function where I load a memory image into the processor, set the program counter, and run a test program on the emulator. This outputs some stuff to the console, and eventually the processor's "HLT" instruction sets "processor.running" to False, terminating processor_thread.

This works OK, but where I'm running in to trouble is a test of restarting the processor by calling run_processor a second time:

processor = Processor(memory, scheduler, interrupts, teleprinter)
processor.program_counter = 128
processor.run_processor()
while processor.processor_thread.isAlive():
    pass
processor.program_counter = 128
processor.run_processor()

The first instance runs fine, but when the run_processor method is called a second time I get the following error:

Exception in thread Thread-3 (most likely raised during interpreter shutdown)

How can I rectify this? Thanks.

EDIT: I broke the code down to its bare essentials and found it actually works OK. I didn't notice that my HALT method was actually written in such a way that it shut down all the processor peripheral threads, including the thread that runs the teleprinter emulator. Without the teleprinter to output to it looks like the emulator core crashed on the second test.

Here's the test case:

import threading
import time

class Processor(object):
    def __init__(self):
        self.running = False

    def halt_processor(self):
        self.running = False

    def run_processor(self):
        processor = self

        class processor_thread(threading.Thread):
            def __init__(self):
                threading.Thread.__init__(self)
                self.daemon = True

            def run(self):
                while processor.running:
                   #main loop for instruction fetch and decode is here   
                   print "Hello, I am the main loop doing my thing 1"
                   time.sleep(1)
                   print "Hello, I am the main loop doing my thing 2"
                   time.sleep(1)
                   print "I will halt now."
                   processor.halt_processor()

        self.processor_thread = processor_thread()
        self.running = True   
        self.processor_thread.start()

def test1():
    processor = Processor()
    processor.run_processor()

def test2():
    processor = Processor()
    processor.run_processor()
    while processor.processor_thread.isAlive():
        pass
    processor.run_processor()

def main():
     test2()

if __name__ == '__main__':
    main()

Works OK.

2
@Wessie But after the first thread has terminated, am I not creating a new thread in the line "self.processor_thread = processor_thread()" during the second call to "processor.run_processor()"? - Bitrex
I'm sorry, I failed to read your code correctly. Disregard that first comment. - Wessie

2 Answers

3
votes

Firstly, you can ignore this error. If your program works, any errors during shutdown could be ignored. I'm fully with you that this isn't the way things should be and that a clean solution is called for.

What I think is missing is the call to thread.join(). You are currently busy-waiting for the thread to return false from isAlive() (which should be is_alive(), btw), using join() is cleaner and shorter.

BTW: There is no need to derive from the Thread class, which makes the code a bit shorter. I personally find it clearer, too, because the Python object is just a handle to the thread and not the thread itself.

0
votes

The way I see it, the main thread ends just after starting again the Processor thread. Have you tried to put a while after starting it?

P.S.: Also, some nice working code would make debugging much easier for those that want to help.