Python Forum

Full Version: how to use thread without locking up terminal
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
Hi, I'm working on a usb project and I'm tying to make it in a way that I can use the terminal while my code is running in the background. for example:
from threading import Thread
import time
a = 0  #global variable
        
def thread1(threadname):
    global a
    while 1:
        a += 1
        time.sleep(1)

thread1 = Thread( target=thread1, args=("Thread-1", ) )
thread1.start()
thread1.join()
print(a)
if I run this idle never reaches print(a). thread1 represents the script that will always be 'looking' at the usb hid device. what I want to do is be able communicate with the hid device being able to use python code via the terminal. similar to when you run a program and it finishes and you can still access your functions and variables. I want 'work' on that end state, or find a way to have that same functionality.
The reason you never reache the print function is that the .join() function waits for every thread to end. the problem is that you run the Thread in an infinite while loop which will never return. If you want to use the join function make sure that your thread dies at some point.
Do you need shared variables like a for what you want to do? If not and you want to kill the thread at some point maybe use multiprocesses. If you want to compute a lot than I would really recommend you to use multiprocessing instead of threads.
yes I need to share variables, I'm basically interacting with a microcontroller and I need to not only send commands but also receive data from it. is it possible to create a thread with an interpreter? that way I can interact with the microcontroller? or if nothing is it possible to run a 'slave' script that with with be threaded by an imported main? ie I have two scripts USBCom.py and Script.py, Script.py imports USBCom.py and is in turn threaded by USBCom.py. I don't think this is possible but I'd like to have a simple interface somehow.
Mmmmmhhhh, using threads makes perfectly sense in this case. Getting data out of the threads into the main program/thread is no problem, just use shared variables or a queue. But giving this thread data while it is running is a different topic. Theoretically queues could work as well here, but maybe Observers and visitors will do the trick
https://python-3-patterns-idioms-test.re...erver.html
When you insert the command via console the programm should interact with the microcontroller, so data has to be send to the thread that manages the microcontroller. I don't know how tricky this is using Observers, but it seems to me, that this is the best way into the thread. I mean that is what it is for. Observers are used while working with GUI where the buttons provide threads themselve. so it should work.
Let me know :)
I'm taking a look at observers on this site: https://www.protechtraining.com/blog/post/879, for some reason some of the code on the other site was giving me an error('mappingproxy' object does not support item assignment) which I'd rather not deal with trying to learn the basic concept. But I'm failing to see how using Observers and visitors are going to 'free up' the terminal. maybe by writing the pywinusb 'receiver' to the observer and have the visitor notified of any change. I'm having a hard time imagining the structure of the program to be able to read and write the microcontroller right now i can only write or listen(which is the hard part)
currently you are running one thread for the terminal and one for the microcontroller "simultaneously" (not really since they are python threads :D), so you are listening for user input and for microcontroller input at the same time. both can send commands/answers and the other side has to react to it. so if the state of the microcontroller changes the user has to be informed and if the user gives input the microcontroller has to react. therefore, the status can change. What do you mean with freeing the terminal? the terminal currently blocks because of the join operation. ignoring the join the terminal should work seperately to the thread. Observer and visitor does not help you to free the terminal, but to enable the communication between the two threads
ok I have a basic idea for communicating using Observers, but I'm having a hard time trying get the scripts talk to each other, so I think I'm making a mistake trying to implement Observers. here is the test code:

User friendly interface:
from Publsr import Publisher, HIDListen, HIDCtrl
import HIDupdater


if __name__ == '__main__':
    global a
    pub = Publisher()
    HID = HIDCtrl('listener')
    
    pub.register(HID, HID.update)
    while 1:
        print(a)
    
    pass
fake hid:
## simulate HID for testing ##
from Publsr import Publisher, HIDListen
from asyncio.tasks import wait

pub = Publisher()
HID = HIDListen('speaker')
pub.register(HID, HID.update)
while 1:
    pub.dispatch("data array []")
    wait(1)
Observer:
class Publisher(object):

    def __init__(self):
        self.subscribers = dict()
    
    def register(self, who, callback=None):
        if callback == None:
            callback = getattr(who, 'update')
        self.subscribers[who] = callback
    
    def unregister(self, who):
        del self.subscribers[who]
    
    def dispatch(self, message):
        for subscriber, callback in self.subscribers.items():
            callback(message)
    
### Script that listens to hid divice ###    
class HIDListen:
    def __init__(self, name):
        self.name = name
    def update(self, message):
        #print('{} got message "{}"'.format(self.name, message))
        a= message 

### User Script (Supposed to be simple for end-user)        
class HIDCtrl:
    def __init__(self, name):
        self.name = name
    def update(self, message):
        print('{} got message "{}"'.format(self.name, message))
        a= message 
actually everything looks fine. One important thing is that you declare a and mark it as global while using it in functions/methods. Here is you code but only with one observer and listener for now:
from asyncio.tasks import wait
import _thread

class Publisher(object):
 
	def __init__(self):
		self.subscribers = dict()
     
	def register(self, who, callback=None):
		if callback == None:
			callback = getattr(who, 'update')
		self.subscribers[who] = callback
     
	def unregister(self, who):
		del self.subscribers[who]
     
	def dispatch(self, message):
		for subscriber, callback in self.subscribers.items():
			callback(message)
     
### Script that listens to hid divice ###    
class HIDListen:
	def __init__(self, name):
		self.name = name
	def update(self, message):
		#print('{} got message "{}"'.format(self.name, message))
		global a
		a= message 
 
### User Script (Supposed to be simple for end-user)        
class HIDCtrl:
	def __init__(self, name):
		self.name = name
	def update(self, message):
	    #print('{} got message "{}"'.format(self.name, message))
		global a
		a= message 

# fake hid
def hid_run(hid):
	pub = Publisher()
	#HID = HIDListen('speaker')
	pub.register(hid, hid.update)
	b = 0
	while 1:
		pub.dispatch(b)
		b += 1
		wait(1)
	

# User friendly interface
a = -1
#pub = Publisher()
HID = HIDCtrl('listener')
_thread.start_new_thread ( hid_run, (HID, ))
#pub.register(HID, HID.update)
while 1:
	print(a)
What's odd is when I separate the script into 3 different files(manly for organizational purposes) and run what is intended to be the users script all I get is -1(so a isn't being updated), running your code, but it works fine when run it all in the same script.
I red some articles stating that it is possible to have a global variable in an extra file. But I could not figure it out. One suggestion I would have is to change the HIDCtrl to
class HIDCtrl:
	def __init__(self, name):
			self.name = name
			self.val = -1
			
	def update(self, message):
			self.val = message 
and your code to:
HID = HIDCtrl('listener')
_thread.start_new_thread ( hid_run, (HID, ))
while 1:
	print(HID.val)
since your publisher is working in the thread, you have your listener recieving your data and one module which is printing it out. The normal approach would be to have a file with the listener and one with the sender. so that the listener can react to actions
Pages: 1 2