首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python中的导入类中运行线程

Python中的导入类中运行线程

原创
作者头像
华科云商小徐
发布2025-01-08 10:56:18
发布2025-01-08 10:56:18
61500
代码可运行
举报
文章被收录于专栏:小徐学爬虫小徐学爬虫
运行总次数:0
代码可运行

在 Python 中使用线程通常涉及到 threading 模块,这是一个用于创建和管理线程的强大工具。如果你的类需要在创建的每个实例中运行一个线程,你可以在类中定义线程的行为,并在类的初始化方法中启动线程。

1、问题背景

在一个项目中,需要使用一个 GSM900 调制解调器和一个树莓派来进行通信。为了方便使用,创建了一个包含相关功能的库 Serialworker.py。在主 Python 应用程序(sniffer.py)中导入该库并使用 serialworker 类中的 start() 函数时,遇到了一个问题:start() 函数一运行,代码就会阻塞,导致无法继续执行后面的代码。

2、解决方案

经过调查,发现问题的原因在于 start() 函数启动了一个线程,而该线程与主线程争用共享资源,导致主线程无法继续执行。为了解决这个问题,需要在 start() 函数中使用适当的锁或条件变量来同步线程之间的访问。

具体代码如下:

代码语言:javascript
代码运行次数:0
运行
复制
class serialworker():
    """This Class instantiates a serial thread and has functions for facilitating communication
    to the serial interface as well as some GSM900 specific functions"""
​
    def __init__(self, port='/dev/ttyAMA0', baud=115200, timeout=5, pollspeed=0.1):
        """Initialises the variables used in this class, baud=, timeout= and pollspeed= can be adjusted
        But have initial values of 115200, 5 and 0.1 respectively, in the future i could add stopbits and parity here"""
​
        self.port = port
        self.baud = baud
        self.timeout = timeout
        self.pollspeed = pollspeed
        self.run = False
        self.ser = serial.Serial
​
        """Command variable description:
        self.command        = Command to write in next while cycle
        self.commandwait    = Bool used to determine if write buffer contains a command for writing in the next while cycle
        self.commandstat    = Variable used to hold the return status of the command that was submitted
        self.commandret     = Bool used to determine if a command was written to the buffer, as to allow the output to be read in the next while cycle
        self.respwait       = Bool used to determine if commandstat is ready to be read
        """
        self.command = ""
        self.commandwait = False
        self.commandstat = ""
        self.commandret = False
        self.respwait = False
        self.lock = threading.Lock()
​
    def start(self):
        """Starts a thread of the _readwriteloop() funtion"""
        #TODO add thread checking, only 1 thread per serial interface should be allowed
​
        self.run = True
        t1 = threading.Thread(target=self.readwriteloop())
        t1.start()
        print("started")
​
    def checkgsm900online(self):
        """Checks if the GSM900 board is online"""
        with self.lock:
            gsmser = serial.Serial(
            port=self.port,
            baudrate=self.baud,
            parity=serial.PARITY_NONE,
            stopbits=serial.STOPBITS_ONE,
            bytesize=serial.EIGHTBITS,
            timeout=self.timeout,)
            gsmcheck = ("AT"+"\r\n").encode()
            gsmser.write(gsmcheck)
            sleep(0.03)
            gsmbuffer = gsmser.inWaiting()
            if gsmbuffer == 0:
                gsmser.flush()
                gsmser.close()
                return False
            else:
                gsmser.flush()
                gsmser.close()
                return True
​
    def check(self):
        """Checks if a thread currently exists"""
​
        return self.run
​
    def stop(self):
        """stops running thread"""
​
        with self.lock:
            self.run = False
​
    def inputcommand(self, string, flag):
        """Allows for a single command to be inputted, sets the commandwait to true to tell the loop to check its queue.
        Optionally you can set flag=False to not wait for a return stat on this command"""
​
        with self.lock:
            self.command = (string+"\r\n").encode()
            self.commandwait = True
            print("waiting for resp")
            if flag:
                while not self.respwait:
                    sleep(0.1)
                self.respwait = False
                return self.commandstat
​
    def readwriteloop(self):
        """Main function of the class that reads serial data from a buffer
        And checks for new commands inputted by the inputcommand() function
        which output status it will write to the commandstat buffer"""
        #TODO write function for retrieving input command return data not just the status
​
        ser = self.ser(
        port=self.port,
        baudrate=self.baud,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS,
        timeout=self.timeout,)
        while self.run:
            with self.lock:
                ser.inWaiting()
                buffer = ser.inWaiting()
                if buffer != 0:
                    decodeline = ser.readline().decode('utf-8', "ignore").rstrip('\n')
                    if len(decodeline) > 2:
                        if self.commandret:
                            if 'ERROR' in decodeline:
                                self.commandstat = decodeline
                                self.commandret = False
                                self.respwait = True
                            elif 'OK' in decodeline:
                                self.commandstat = decodeline
                                self.commandret = False
                                self.respwait = True
                            elif 'NO CARRIER' in decodeline:
                                self.commandstat = decodeline
                                self.commandret = False
                                self.respwait = True
​
                if self.commandwait:
                    ser.write(self.command)
                    #print(self.command)
                    self.commandwait = False
                    self.commandret = True
            sleep(self.pollspeed)

在更新后的代码中,在 start() 函数和 checkgsm900online() 函数中添加了锁。这样,在访问共享资源时,线程就会被同步,从而避免了争用问题。现在,start() 函数将不再阻塞主线程,代码可以正常运行。

要注意的是,在 Python 中使用锁时,必须确保在所有可能导致死锁的地方释放锁。在上面的代码中,锁只在 start() 函数和 checkgsm900online() 函数中使用,因此不会出现死锁问题。如果需要在代码的其他部分使用锁,则必须确保在适当的地方释放锁。

通过这种方式,你可以在 Python 中有效地使用面向对象的方法来管理多线程任务,提高程序的并发性能和响应速度。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档