ti-enxame.com

Sinais Qt (QueuedConnection e DirectConnection)

Estou tendo problemas com os sinais do Qt.

Eu não entendo como DirectConnection e QueuedConnection funcionam?

Eu ficaria grato se alguém explicasse quando usar qual destes (código de amostra seria apreciado).

40
Nika

Você não verá muita diferença a menos que esteja trabalhando com objetos com diferentes afinidades de thread. Digamos que você tenha QObjects A e B e ambos estejam anexados a diferentes threads. A tem um sinal chamado somethingChanged() e B tem um slot chamado handleChange().

Se você usa uma conexão direta 

connect( A, SIGNAL(somethingChanged()), B, SLOT(handleChange()), Qt::DirectConnection );

o método handleChange() será executado na thread do A. Basicamente, é como se a emissão do sinal chamasse o método de slot "diretamente". Se B::handleChange() não é thread-safe, isso pode causar alguns erros (difíceis de localizar). No mínimo, você está perdendo os benefícios do segmento extra.

Se você alterar o método de conexão para Qt::QueuedConnection (ou, nesse caso, deixe o Qt decidir qual método usar), as coisas ficarão mais interessantes. Assumindo que o encadeamento de B esteja executando um loop de eventos, a emissão do sinal postará um evento no loop de eventos de B. O loop de eventos enfileira o evento e, eventualmente, chama o método de slot sempre que o controle retorna para ele (sendo o loop de eventos). Isso torna muito fácil lidar com a comunicação entre/entre threads no Qt (novamente, supondo que seus threads estejam executando seus próprios loops de eventos locais). Você não precisa se preocupar com bloqueios, etc., porque o loop de eventos serializa as chamadas do slot.

Nota: Se você não souber como alterar a afinidade de thread de um QObject, procure em QObject::moveToThread. Isso deve começar.

Editar

Eu deveria esclarecer minha sentença inicial. Isso faz diferença se você especificar uma conexão enfileirada - mesmo para dois objetos no mesmo encadeamento. O evento ainda é postado no loop de eventos do encadeamento. Portanto, a chamada do método ainda é assíncrona, o que significa que ela pode ser atrasada de maneiras imprevisíveis (dependendo de qualquer outro evento que o loop precise processar). No entanto, se você não especificar um método de conexão, o método direto será usado automaticamente para conexões entre objetos no mesmo thread (pelo menos no Qt 4.8).

70
Jacob Robbins

além da resposta de Jacob Robbins:

a declaração "Você não verá muita diferença a menos que esteja trabalhando com objetos que possuem diferentes afinidades de encadeamento" é errado;

emitir um sinal para uma conexão direta dentro do mesmo thread executará o slot imediatamente, assim como uma simples chamada de função.

emitir um sinal para uma conexão enfileirada no mesmo encadeamento enfileirará a chamada no loop de eventos de encadeamentos, assim a execução always acontecerá atrasada.

A classe baseada em QObject possui uma conexão enfileirada para si mesma

21
t_3

A resposta de Jacob é incrível. Gostaria apenas de adicionar um exemplo comparativo à programação incorporada.

Vindo de um background RTOS/ISR embutido, foi útil ver as similaridades no DirectConnection do Qt para o comportamento preemptivo dos ISRs e o QueuedConnection do Qt para mensagens na fila em um RTOS entre as tarefas.

Nota: Vindo de um fundo Embedded, é difícil para mim não definir o comportamento na programação. Eu nunca deixo o argumento como Auto, mas isso é apenas uma opinião pessoal. Eu prefiro tudo para ser explicitamente escrito, e sim, isso fica difícil às vezes!

0
user3934527