AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79575015
Accepted
ShawnM
ShawnM
Asked: 2025-04-15 19:21:51 +0800 CST2025-04-15 19:21:51 +0800 CST 2025-04-15 19:21:51 +0800 CST

Como posso colocar sinais Python em uma fila com segurança?

  • 772

Estou trabalhando em um script python3 que manipula sinais (por exemplo, signal.SIGWINCH) colocando-os em uma fila. Uma thread separada coloca a entrada do usuário na mesma fila, que é toda processada pela thread principal do meu programa.

Ocasionalmente, o programa inteiro trava repentinamente. Identifiquei a causa como sendo a interação entre os manipuladores de sinais e a queue.Queueclasse. Após um pequeno número aleatório de sinais ser enfileirado, o manipulador de sinais bloqueia a fila ao tentar inserir um item nela. Qualquer thread que tente interagir com a fila de qualquer forma (por exemplo, chamando queue.put(block=False), queue.get(block=False)ou queue.empty()) também trava.

Por que os manipuladores de sinais bloqueiam minha fila, mesmo quando uso funções não bloqueantes? Existe uma maneira segura de adicionar sinais a uma fila em um programa multithread?


Isso pode ser reproduzido executando o trecho de código simplificado abaixo, enquanto redimensiona repetidamente o terminal para acionar o evento (testado em python 3.13, linux):

from queue import Queue, Empty
import signal

event_queue = Queue()

def signal_handler(signum, frame):
    event_queue.put(signum)

signal.signal(signal.SIGWINCH, signal_handler)

while True:
    try:
        print("Attempting to get an event from the queue...")
        evt = event_queue.get(block=False)
        print("Successfully got event from the queue.")
    except Empty:
        print("The queue is empty, try again.")

Eventualmente, após redimensionar a janela um número indeterminado de vezes, o código trava após a linha "Tentando obter um evento da fila..."; ou seja, trava em queue.get(). Mas não deveria, já que especifiquei block=False. Também tentei usar event_queue.put(signum, block=False)no meu manipulador de sinais dentro de um try/except, mas ainda trava.

(...)
Attempting to get an event from the queue...
The queue is empty, try again.
Attempting to get an event from the queue...
(code hangs indefinitely)

Se eu mudar para multiprocessing.Queueou usar queue.get(timeout=0.1), aparentemente não terei mais esse problema. Mas ambas as abordagens têm um custo/atraso de velocidade substancial, e estou preocupado se alguma delas é totalmente segura, já que até mesmo queue.Queueé supostamente seguro para threads .

python-3.x
  • 2 2 respostas
  • 86 Views

2 respostas

  • Voted
  1. Best Answer
    user2357112
    2025-04-15T19:38:56+08:002025-04-15T19:38:56+08:00

    queue.QueueAs filas são seguras para threads. Mas você precisa de reentrada , que é um requisito ainda mais difícil.

    Quando um manipulador de sinais é executado, ele assume o controle de uma thread, interrompendo qualquer trabalho que esteja sendo executado nela. Todos os tipos de estruturas de dados podem estar em estados inconsistentes nesse ponto. Bloqueios não resolvem o problema, pois um manipulador de sinais pode interromper uma thread enquanto ela mantém um bloqueio e executar nessa thread , com o bloqueio mantido, enquanto quaisquer invariantes que o bloqueio deveria proteger são quebradas.

    Neste caso, parece que o seu manipulador de sinais está interrompendo a sua getchamada, enquanto mantém o bloqueio da fila. O seu manipulador de sinais tenta chamar put, que tenta obter o bloqueio da fila novamente. Como o bloqueio da fila é um bloqueio não reentrante, o manipulador de sinais entra em deadlock.


    Se você precisar de uma fila com a qual seja possível interagir com segurança a partir de manipuladores de sinais, o queuemódulo fornece queue.SimpleQueueisso. queue.SimpleQueueEle foi projetado especificamente para que putpossa ser chamado com segurança a partir de um thread que já esteja executando outra chamada putou .get

    Observe que queue.SimpleQueueé preciso se limitar a uma API mais simples para poder garantir essa segurança. Por exemplo, não há como tornar puta reentrada segura com uma fila delimitada, portanto, queue.SimpleQueuenão há suporte para limites de tamanho.

    • 1
  2. ShawnM
    2025-04-16T09:19:00+08:002025-04-16T09:19:00+08:00

    A solução mais fácil seria usar SimpleQueue, conforme sugerido pela resposta do usuário2357112 - mas preciso manter o suporte para python <3.7, que não o inclui.

    Após ler mais sobre reentrada em Python , descobri que sinais só podem ser acionados entre operações atômicas. Assim, troquei de fila para deque :

    uma implementação alternativa de filas ilimitadas com operações atômicas rápidas append() e popleft() que não exigem bloqueio e também suportam indexação.

    ...tornando-o seguro em relação a threads e sinais para meus propósitos, ao mesmo tempo em que ainda é O(1) nessas operações.

    Isso difere do bloqueio do queue.py, que utiliza threading.Lockem vez do GIL e, portanto, pode ser interrompido por sinais.


    Código atualizado para usar deque para manipulação de sinais:

    import signal
    from collections import deque
    
    event_queue = deque()
    
    def signal_handler(signum, frame):
        event_queue.append(signum)
            
    signal.signal(signal.SIGWINCH, signal_handler)
    
    while True:
        if event_queue:
            evt = event_queue.popleft()
            print(f"Got an event: {evt}")
    
    • 0

relate perguntas

  • Preenchendo valores ausentes no dataframe do Pandas usando outro dataframe

  • Comparando e classificando valores em duas colunas de um DataFrame e classificando na mesma linha em python

  • Esta versão do ChromeDriver suporta apenas 114

  • Por que lista vazia para funcionar?

  • A configuração do Python-Django Multi-Index of Pandas DataFrame não agrupa/mescla o último índice

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve