2012-02-20 37 views
5

Tôi đang cố gắng tìm hiểu rõ hơn về tín hiệu và khe Qt cùng với chuỗi. Vì vậy, tôi đã cố gắng ứng dụng tối thiểu này:Chuỗi Qt không dừng lại sau khi gọi thoát/thoát

foo.h:

#include <QObject> 

class A : public QObject { 
    Q_OBJECT 

public: 
    void doit(); 

signals: 
    void x(); 
}; 

class B : public QObject { 
    Q_OBJECT 

public slots: 
    void h(); 
}; 

Foo.cpp:

#include "foo.h" 

#include <QThread> 
#include <QCoreApplication> 

void B::h() { 
    qDebug("[%d] B::h() here!", (int) QThread::currentThreadId()); 
    QCoreApplication::instance()->quit(); 
} 

void A::doit() { 
    qDebug("[%d] emitting...", (int) QThread::currentThreadId()); 
    emit x(); 
} 

int main(int argc, char* argv[]) { 
    QCoreApplication app(argc, argv); 
    A a; 
    B b; 
    QObject::connect(&a, SIGNAL(x()), &b, SLOT(h())); 
    QThread t; 
    t.start(); 
    b.moveToThread(&t); 
    a.doit(); 
    t.wait(); 
    return 0; 
} 

Mọi thứ đều tốt đẹp, chỉ có t.wait() ở cuối không bao giờ trở lại. Sự hiểu biết của tôi là gọi quit() nên dừng vòng lặp sự kiện, có nghĩa là exec() sẽ trở lại và do đó nên chạy() và thực hiện luồng nên dừng lại. Tui bỏ lỡ điều gì vậy?

+3

tên của các phương pháp của bạn nên làm rõ mục đích của chúng. – UmNyobe

+0

Đừng lo, đây không phải là mã sản xuất! Tôi thấy tên giả mạo hoạt động tốt hơn nhiều trong mã mẫu/thử nghiệm ngắn, hơn là tên mô tả giả tạo. – Elektito

+0

Tôi đồng ý với UmNyobe. Sẽ dễ dàng hơn khi đọc và hiểu mã mẫu nếu bạn sử dụng nhiều tên thông tin hơn. Ví dụ. A :: doit() -> A :: emitThreadStart(), void x() -> startThread(), void h() -> void quitApplication() ... etc – Dmitriy

Trả lời

10

QCoreApplication::quit() không được nêu là phương pháp an toàn theo luồng nên bạn không thể gọi nó từ một chuỗi khác. Ứng dụng của bạn có thể gặp sự cố hoặc có hành vi không xác định (UB).

t.wait() sẽ không bao giờ trở lại vì chuỗi đang chạy liên tục chờ sự kiện. Để ngăn chặn các chủ đề mà bạn phải gọi QThread::quit() [slot]

Nếu bạn muốn thoát khỏi ứng dụng sau khi công việc được thực hiện, bạn phải phát ra một tín hiệu, được kết nối với QCoreApplication::quit() [static slot]

Nếu bạn muốn dừng các sợi nhân sau công việc được thực hiện bạn cũng đã phát ra một tín hiệu, kết nối với void QThread::quit() [slot]

Added: Threads, Events and QObjects cho đọc thêm

Lưu ý quan trọng: bạn phải gọi QCoreApplication::exec() i Để có thể sử dụng tín hiệu & cơ chế khe giữa các luồng, các kết nối được xếp hàng đợi.

Từ Qt QThread doc:

Mỗi QThread có thể có vòng lặp sự kiện riêng của mình. Bạn có thể bắt đầu vòng lặp sự kiện bằng cách gọi hàm exec(); bạn có thể dừng nó bằng cách gọi exit() hoặc quit().Có vòng lặp sự kiện trong một chuỗi làm cho nó có thể kết nối các tín hiệu từ các luồng khác vào các khe trong chuỗi này, sử dụng một cơ chế được gọi là xếp hàng kết nối. Nó cũng làm cho nó có thể sử dụng các lớp đòi hỏi vòng lặp sự kiện , chẳng hạn như QTimer và QTcpSocket, trong chuỗi. Lưu ý, tuy nhiên, không thể sử dụng bất kỳ lớp tiện ích con nào trong chuỗi .

Doc cho Qt :: QueuedConnection:

Khe cắm được gọi khi kiểm soát trở về vòng lặp trường hợp chủ đề của người nhận. Khe được thực hiện trong luồng của máy thu .

+0

Bạn đã đúng. Tôi không dừng vòng lặp sự kiện chính xác. Thật không may, UmNyobe đã chỉ ra điều này trước mặt bạn, vì vậy tôi phải chấp nhận câu trả lời của họ. Tôi đang upvoting trả lời của bạn mặc dù, vì nó rõ ràng hơn. Cảm ơn bạn. – Elektito

+0

Suy nghĩ thứ hai, tôi nghĩ rằng tôi nên chấp nhận câu trả lời của bạn, vì người kia có nhiều thông tin sai lạc và có thể khá khó hiểu đối với những người khác đang đọc nó. – Elektito

+0

Về thông báo đã thêm của bạn, trong đoạn mã của tôi, tôi chưa gọi 'QCoreApplication :: exec()' nhưng các tín hiệu/vị trí hoạt động. Dường như với tôi rằng vòng lặp sự kiện bên trong QThread đủ. – Elektito

2

Có vẻ như có nhiều điều sai với mã của bạn.

  • Bạn không gọi app.exec(). Có nghĩa là không có vòng lặp sự kiện chính. Tín hiệu x của A sẽ không được phát ra.
  • Theo mặc định, một chuỗi has it's own even loop trong Qt (ít nhất là từ vài năm). Sau đó, bắt đầu một cuộc gọi thread Qthread::run() và vòng lặp sự kiện được bắt đầu. Đó là nơi mà chủ đề của bạn, không phải trong t.wait().
  • Mục đích của t.wait() là gì? Tôi tin rằng bạn đang lạm dụng nó.
  • (Nếu mọi thứ khác đều ổn), trong B::h() bạn đang dừng chuỗi chính từ chuỗi khác. Đó có phải là điều bạn muốn làm không?

Vì vậy, lời khuyên đầu tiên của tôi là thêm app.exec(), xem cách ứng xử hoạt động. Giải thích những gì bạn đang cố gắng làm, và viết lại một cái gì đó khác. Bởi vì you're doing it wrong

+0

t.start() gọi phương thức run() có thực thi mặc định gọi exec(). Như tôi đã nói, các tín hiệu _are_ phát ra và nhận được một cách chính xác. wait() là tương đương với pthread_join, hoặc vì vậy tài liệu nói, vì vậy tất cả những gì tôi đang làm là đợi cho đến khi luồng kết thúc. Cuối cùng, điểm cuối cùng của bạn là chính xác. Tôi không dừng vòng lặp sự kiện luồng. Thay đổi dòng đó thành 'QThread :: currentThread() -> quit()' thực hiện thủ thuật. Cảm ơn bạn. – Elektito

+0

exec() tiếp tục chạy để wait() không có hiệu ứng. – UmNyobe

+0

Đó là sự thật của khóa học, nhưng ý định chờ đợi() là chờ đợi cho kết thúc exec(), do đó, sử dụng wait() là không sai cho mỗi se; không dừng vòng lặp sự kiện đúng. – Elektito

Các vấn đề liên quan