何时在线程化的Python类中需要互斥锁?

时间:2018-10-31 11:58:41

标签: python multithreading mutex

我有一个控制旋转机械编码器的类。事物的更新方面(读取状态,推断增量和更新steps属性)在单独的线程中处理,更新的step值在get_steps中传递出去。 button_callback函数也通过GPIO.add_event_detect的宽限度在单独的线程中处理。根据{{​​3}},我使用了两个互斥对象,因为主线程读取或重置属性的时间可能不确定:

第一个是通过按编码器按钮来控制所传递的button_callback函数的执行-所传递的函数可能会编辑一个全局变量,也可以由主线程的其他元素来作用。我知道button_lock将需要在主线程中的其他位置部署相关的变量,但是我相当有信心。

第二个方法是控制对属性steps的访问,特别是停止reset方法(可能由主线程调用),从而在更新周期中更改step属性。我不确定这里和get_steps方法中的任何操作都是原子操作,或者是否需要互斥锁。

import RPi.GPIO as GPIO
import math
from threading import Thread, Lock
import time


class Encoder:
    enc_A = 27
    enc_B = 17
    switch = 4

    def __init__(self, button_callback=None, button_args=None):
        GPIO.setwarnings(True)
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self.enc_A, GPIO.IN)
        GPIO.setup(self.enc_B, GPIO.IN)
        if button_callback is not None:
            GPIO.setup(self.switch, GPIO.IN)
            self.button_lock = Lock()

            def cb(channel):
                with self.button_lock:
                    return button_callback(channel, button_args) if button_args is not None else button_callback(channel)
            GPIO.add_event_detect(self.switch, GPIO.FALLING, callback=cb)
        self.lock = Lock()
        self.r_seq = self.get_rseq()
        self.last_delta = 0
        self.reset()
        self.threadRun = False
        self.start()

    def get_rseq(self):
        a = GPIO.input(self.enc_A)
        b = GPIO.input(self.enc_B)
        return (a ^ b) | b << 1

    def update(self):
        while self.threadRun:
            r_seq = self.get_rseq()
            delta = 0
            if r_seq != self.r_seq:
                delta = (r_seq - self.r_seq) % 4
                if delta == 3:
                    delta = -1
                elif delta == 2:
                    delta = int(math.copysign(delta, self.last_delta))
                self.last_delta = delta
                self.r_seq = r_seq
            with self.lock:
                self.steps += delta
            time.sleep(0.002)
        GPIO.remove_event_detect(self.switch)
        GPIO.cleanup()

    def get_steps(self):
        with self.lock:
            return self.steps

    def reset(self):
        with self.lock:
            self.steps = 0

    def stop(self):
        self.threadRun = False

    def start(self):
        self.threadRun = True
        Thread(target=self.update).start()

我希望此代码尽可能简单明了,并且使用Python语言编写,其中包括正确使用互斥量。就目前的情况而言,对于我的用法,此代码有效,但是我对寻求良好的实践非常感兴趣,因此在这种情况下,我很乐意听取建议。

注意:编码器的处理基于Python 3 FAQs-作者的贡献。

0 个答案:

没有答案