2012-02-03 3 views
2

QThread 및 슬롯/신호 메커니즘을 사용하고 있습니다. 나는 lot이 웹에 관한 스레드를 알고 있으며, 특히 여기에서는 그렇다.하지만 여전히 해결책을 찾지 못했다. 어쨌든 여기에는 상황이 있습니다.다른 스레드에서 작동하는 QObject를 제어하고 이벤트 대기열을 우회하여 GUI를 고정시킵니다.

제가 생각해 내려고하는 코드는 GUI가 결국에는 긴 프로세스이므로 제어를 목표로하므로 QThread을 사용합니다.

두 개의 버튼이있는 창을 시작 및 중지합니다. 내 WindowQThreadTask이며, 후자는 QObject에서 상속받습니다. 실행되는 동안 내 작업을 중지하고 이미 실행 중일 때 시작을 클릭하면 다시 시작하지 못하게하고 싶습니다.

class Window: public QWidget 
{ 
public: 

    Window() 
    { 
    // Instantiate buttons and put them in a layout. 
    // ... 

    connect(buttonStart_, SIGNAL(clicked()), &task_, SLOT(startTask())); 
    connect(buttonStop_, SIGNAL(clicked()), &task_, SLOT(stopTask()), 
      Qt::DirectConnection); 

    task_.moveToThread(&thread); 
    thread_.start(); 
    } 

private: 
    QPushButton buttonStart_; 
    QPushButton buttonStop_; 

    QThread thread_; 
    Task task_; 
}; 

I : 내 Window의 생성자에서 버튼과 작업 사이에 두 개의 연결을 만든

class Task: public QObject 
{ 
public: 

    Task(): QObject(), stop_(true) {} 

private slots: 

    void startTask() 
    { 
    stop_ = false; 
    run(); 
    } 

    void stopTask() 
    { 
    stop_ = true; 
    } 

    void run() const 
    { 
    while (! stop_) 
    { 
     sleep(1); 
    } 
    } 

    bool stop_; 
}; 

: 여기

는 (긴 과정을 가짜) Task의 발췌 한 것입니다 Qt::DirectConnection을 두 번째로 사용했습니다 connect() 내 신호를 처리하도록 요청하는 신호를 "강제로"처리하기 때문에 (이해할 수있는 것처럼) task_은 이벤트를 처리하기 전에 작업에서 복귀해야합니다. 어 (기본 연결을 사용하는 경우 내 작업이 완료된 후 모든 클릭이 처리됩니다).

여기에서 Qt::DirectConnection은 이벤트 대기열을 "바이 패스"하여 작업을 중지 할 수 있습니다. 그러나 솔직히 말해서 그것이 적절한 방법인지 또는 해결 방법 (따라서 내 문제의 근원 일 가능성이 있음)인지는 알 수 없습니다.

어쨌든,이 방법은 정상적으로 작동하지만 버튼을 가지고 놀기 시작하면 GUI가 결국 멈추게됩니다. 내 문제입니다!

도움이 될 것입니다. 시간 내 줘서 고마워!

답변

4

DirectConnection을 사용하면 슬롯이 UI 스레드에서 실행된다는 것을 의미합니다 (작업 스레드가 아직 실행 중일 때). 이것은 당신이 원하는 것이 아닙니다. 이 문제를 처리하는 방법은 QThread::exec()을 실행하여 스레드에서 이벤트 루프를 사용하는 것입니다.

스레드가 원하는대로 응답 할 수있게하려면 스레드가 들어오는 이벤트를 처리 할 수 ​​있어야합니다. 이 문제를 처리 할 수있는 몇 가지 방법이 있습니다. 하나는 작업이 실행되는 동안 때때로 QCoreApplication::processEvents()으로 전화하는 것입니다. 다른 하나는 일부 처리를 수행하는 슬롯에 QTimer을 연결하는 것입니다.중요한 것은 스레드의 이벤트 루프를 실행할 수 있는지 확인하는 것입니다.

+0

내'Task :: run()'메서드가 내 스레드가 신호를 처리하지 못하게한다는 것을 의미합니까? 당신의 대답에서 이해할 수있는 것은'while' 루프가 정기적으로'processEvents()'(또는 유사)를 호출해야한다는 것입니다. 나 맞아? – piwi

+0

예, 작업이 스레드 내부에서 실행중인 경우 스레드는 사용자가 말하지 않는 한 다른 작업을 수행 할 수 없습니다. while 루프에서'processEvents()'를 호출하면 스레드가 exec()로 시작 되었다면 작동합니다. ETA : 방금 알게 된 것, QThread :: run()은 이미 exec()를 호출하므로 해당 부분이 작동합니다. DirectConnection을 제거하고 작업의 run() 루프에서 processEvents()를 호출하면됩니다. –

+0

매력처럼 작동합니다. 고마워요! – piwi

2

당신이 이해할 필요가 우선은 실 사용자의 신호/슬롯 연결이 실행되고있는 것입니다.

이 특별한 경우의 기본 동작은 수신에 당신의 신호 이벤트를 넣어 것입니다 Qt::QueuedConnection을 사용하는 것입니다 thread의 이벤트 큐 Qt::DirectConnection의 경우 슬롯은 신호을 내 보낸 객체의 스레드에서 으로 실행됩니다.

Qt :: DirectConnection을 사용하면 stop_ 변수 주위에 뮤텍스를 넣어 두 스레드가 동시에 액세스하지 못하게하는 경우에만이 인스턴스에서만 안전합니다.

+0

사실 저는'stop_' 변수 주위에 뮤텍스를 넣으려고했지만 문제를 해결하지 못했습니다 ('Task'는'QMutex' 멤버를 얻고'stop_' 조작은'lock()'와'unlock()')을 사용한다. 그러나'Qt :: QueuedConnection'을 사용하면받는 작업 스레드 (내 작업 전용 스레드)가 내 작업이 끝난 후에 만 ​​내 프로세스를 처리하게됩니다. 나는 그것이 작동하는 동안 그것을 처리하고 싶다. – piwi