簡體   English   中英

使用Python,如何防止兩個線程同時寫入顯示

[英]With Python, how to prevent two threads from writing simultaneously to display

我正在一個Raspberry Pi項目中,在這里我有一個OLED顯示器,它在True-loop時不斷地用Python中的信息進行更新。 但是,每當我按下按鈕(GPIO 5)時,只要按下按鈕,或者可能在預定的時間段內,我都希望顯示一些其他靜態信息(例如,系統信息)。 釋放按鈕后,“主循環”可能會再次接管。 我試圖使用RPi.GPIO和回調函數來實現此功能以顯示系統信息,但是問題是,即使在執行回調函數期間,主循環仍會繼續寫入OLED,如果按下GPIO 5:兩個“線程”都同時寫入OLED ...

我假設我需要一種在回調函數期間暫停主循環執行的方法,並且我已經嘗試過信號量和獲取/釋放,但是沒有運氣。 我還考慮了將兩個回調函數與Semaphore結合使用的可能性,但是由於主循環中顯示的信息應該不斷更新(例如,不是由中斷驅動),所以我不確定這是否是我的解決方案。

在這一點上,我什至不知道下一步該怎么做。 也許這里有人可以啟發我? 這是做這種事情的完全錯誤的方式嗎? (Python的有限經驗...)

下面是一個簡化的代碼示例,它模擬了我想做的事情。

import time
import Adafruit_GPIO.SPI as SPI
import RPi.GPIO as GPIO
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

# Initialize
disp = Adafruit_SSD1306.SSD1306_128_64(rst=None)
disp.begin()
disp.clear()
disp.display()
image = Image.new('1', (disp.width, disp.height))
draw = ImageDraw.Draw(image)
font = ImageFont.load_default()
GPIO.setmode(GPIO.BCM) 
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up

def clear_display():
    draw.rectangle((0,0,disp.width,disp.height), outline=0, fill=0)
    disp.image(image)
    disp.display()

# Callback function 
def display_system_info(channel):
    draw.text((0, 0), "System info displayed",  font=font, fill=255)
    draw.text((0, 9), "for five seconds.",  font=font, fill=255)
    disp.image(image)
    disp.display()
    time.sleep(5)
    clear_display()

GPIO.add_event_detect(5, GPIO.RISING, callback=display_system_info, bouncetime=200)

try:
    while True:
        for counter in range(7):
            draw.text((0,counter*9), "Printing line {0:d}".format(counter),  font=font, fill=255)
            disp.image(image)
            disp.display()
            time.sleep(1)
        clear_display()
except KeyboardInterrupt:  
    GPIO.cleanup()       # clean up GPIO on CTRL+C exit
GPIO.cleanup()           # clean up GPIO on normal exit  

非常感謝您的幫助。

/ N

我正在使用全局varialbe-buttonPressed解決這種情況。 當您按下按鈕(GPIO 5)時,buttonPressed設置為True,主循環不執行任何操作。 希望對您很清楚,對您有幫助。

import time
import Adafruit_GPIO.SPI as SPI
import RPi.GPIO as GPIO
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

# Initialize
disp = Adafruit_SSD1306.SSD1306_128_64(rst=None)
disp.begin()
disp.clear()
disp.display()
image = Image.new('1', (disp.width, disp.height))
draw = ImageDraw.Draw(image)
font = ImageFont.load_default()
GPIO.setmode(GPIO.BCM) 
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up

buttonPressed = False

def clear_display():
    draw.rectangle((0,0,disp.width,disp.height), outline=0, fill=0)
    disp.image(image)
    disp.display()

# Callback function 
def display_system_info(channel):
    global buttonPressed
    buttonPressed = True
    draw.text((0, 0), "System info displayed",  font=font, fill=255)
    draw.text((0, 9), "for five seconds.",  font=font, fill=255)
    disp.image(image)
    disp.display()
    time.sleep(5)
    clear_display()
    buttonPressed = False

GPIO.add_event_detect(5, GPIO.RISING, callback=display_system_info, bouncetime=200)

try:
    while True:
        if(not buttonPressed):
            for counter in range(7):
                draw.text((0,counter*9), "Printing line {0:d}".format(counter),  font=font, fill=255)
                disp.image(image)
                disp.display()
                time.sleep(1)
            clear_display()
except KeyboardInterrupt:  
    GPIO.cleanup()       # clean up GPIO on CTRL+C exit
GPIO.cleanup()           # clean up GPIO on normal exit  

嘗試讓我知道。

根據您的應用程序,我將避免在回調內部進行任何實際工作。 相反,我只設置一個主線程/循環可以處理的標志或將事件添加到由主線程/循環處理的隊列中。

我意識到,對於該特定應用程序而言,中斷並不是走好的路。 取而代之的是,我重新編寫了代碼,以便僅在主循環空閑並等待時才按下按鈕……這當然是大多數時間。 感謝您的輸入!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM