简体   繁体   English

当 docker 容器停止时,GPIO 引脚保持开启状态

[英]GPIO pins staying on when docker container is stopped

I am running a simple python script in a docker container to turn some GPIO Leds on.我在 docker 容器中运行一个简单的 python 脚本来打开一些 GPIO LED。 I am using the gpiozero library.我正在使用gpiozero库。 The script runs fine and works as expected in the container.该脚本运行良好,并在容器中按预期工作。 The issue is that when I abruptly stop the container, the LEDs stay on.问题是当我突然停止容器时,LED 会一直亮着。 Here is the code for GPIO.这是 GPIO 的代码。

from gpiozero import PWMLED
from gpiozero import LEDBoard
from time import sleep

leds = LEDBoard(12, 16)
freq = 1

for led in leds:
    led.on()

sleep(1000)

for led in leds:
    led.off()

And here is my Dockerfile.这是我的 Dockerfile。

from arm64v8/python:3.10-alpine3.15

RUN pip install gpiozero
RUN mkdir /app
COPY bread_pi.py /app/bread_pi.py
WORKDIR /app
CMD ["python3", "bread_pi.py"]

When I run the program on the machine locally (no docker), it behaves as expected and when I terminate the program abruptly with Control+C the GPIO pins and their respective LEDs turn off.当我在机器上本地运行程序(没有 docker)时,它的行为符合预期,当我使用Control+C突然终止程序时,GPIO 引脚及其各自的 LED 熄灭。 When I stop the docker container with docker stop , the container stops successfully but the GPIO pins remain On.当我使用docker stop停止 docker 容器时,容器成功停止但 GPIO 引脚保持打开状态。 Is there a correct way to gracefully terminate a python program running in a docker container?是否有正确的方法可以优雅地终止在 docker 容器中运行的 python 程序?

Hardware: -Rasberry PI Compute Module 4 and IO board -BreadPi PiHAT硬件:-Rasberry PI 计算模块 4 和 IO 板 -BreadPi PiHAT

Software: -python3.10 -Docker 20.10.18软件:-python3.10 -Docker 20.10.18

Because your program seems to behave as expected when abruptly stopped does not mean it does a clean stop..因为你的程序在突然停止时似乎表现得像预期的那样并不意味着它会干净地停止..

When a docker container is requested to stop, it sends a SINGINT to the running processes.当请求停止 docker 容器时,它会向正在运行的进程发送一个 SINGINT。 In order to stop gracefully, you may want to catch that signal from your Python application and execute accordingly to release the GPIO signals level.为了优雅地停止,您可能需要从 Python 应用程序捕获该信号并相应地执行以释放 GPIO 信号电平。

As for an example, here is how you can catch the SIGINT for a threaded application:举个例子,下面是如何捕获线程应用程序的 SIGINT:

import logging
import signal
import threading

# keep the application alive until explicitly stated otherwise
semaphore = threading.Semaphore(value=0)

# notes:
# - you have to implement your blink thread inheriting from
# the standard class `threading.Thread`.
# - you have to implement  a function `stop_request` which stops
# the thread execution.
t = BlinkThread()

# register event handler for CTRL+C
def handler(signum, frame):
    logging.fatal("received stop request, terminating application...")

    # wait for your thread to stop
    t.request_stop()
    t.join()

    # notify application can stop
    semaphore.release()

signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)

# start your application thread initialized earlier
t.start()

# wait for quit request to be received
semaphore.acquire()
return 0

To give you a full example, here is a stoppable thread and a blink thread example implementation classes:为了给你一个完整的例子,这里有一个可停止线程和一个闪烁线程示例实现类:

class StoppableThread(threading.Thread):
    """
    Stoppable thread can be started and stopped in a clean way.
    """

    def __init__(self):
        """
        Create a stoppable thread ready to execute upon start().
        """
        threading.Thread.__init__(self)
        self.running = True

    def request_stop(self, blocking=True):
        """
        Stop the current thread and wait or it to complete.
        """
        self.running = False
        if (blocking):
            self.join()

    def is_running(self):
        """
        Check whether the thread is expected to keep running.
        @return True to keep execution running, False otherwise.
        """
        return self.running

    def not_running(self):
        """
        Mark the thread as not running anymore. This function can be called
        when the thread exits its main loop if ever the request_stop() function
        has not been called.
        """
        self.running = False

    def run(self):
        pass

class BlinkThread(StoppableThread):
    def __init__(self, leds, period_ms):
        StoppableThread.__init__(self)

        self.leds = leds
        self.period_ms = period_ms

    def run(self):
        while self.is_running():
            for led in self.leds:
                led.on()
            sleep(self.period_ms)

            for led in self.leds:
                led.off()
            sleep(self.period_ms)

        self.not_running()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM