2017-11-23 96 views
2

안녕하세요, 백그라운드에서 소켓 통신을해야하는데, QtConcurrent::run을 사용했지만 경고 메시지를 전합니다. 여기 QObject 다른 스레드에있는 부모를위한 자식을 만들 수 없습니다.

QObject: Cannot create children for a parent that is in a different thread. 
(Parent is MainWindow(0x7fff3e69f500), parent's thread is QThread(0x16f8070), current thread is QThread(0x17413d0) 

MainWindow::MainWindow(QWidget *parent) : 
QMainWindow(parent),ui(new Ui::MainWindow){ 
     ui->setupUi(this); 
     QFuture<void> f2 = QtConcurrent::run(this,&MainWindow::checkCamStatus); 
    } 


void MainWindow::checkCamStatus(){ 
    while(1){ 
     bool flag = false; 
     QTcpSocket* socket = new QTcpSocket(this); 
     socket->moveToThread(this->thread()); 
     socket->setParent(this); 
     socket->connectToHost("10.0.7.112", 80); 
     if(socket->waitForConnected(1000))//check for connection for i second 
     { 
     qDebug() << "Cam online"; 
     } 
     else{ 
     qDebug() << "..............................Cam offline"; 
     } 

     QThread::sleep(1); 
    } 
} 

가 어떻게 경고를 제거 할 수 있습니다, 코드인가?

+4

문제는 무엇입니까?경고를 없애려면 부모를 설정하지 마십시오. –

+0

예 경고를 제거해야합니다. – Haris

+1

부모를 사용하여 다른 스레드의 개체를 삭제할 수 없습니다. 'deleteLater()'메소드를 사용하면 이벤트 대기열에서 객체를 삭제할 수 있습니다. –

답변

2

첫째,.

socket->moveToThread(this->thread()) 뒤에 socket의 함수 멤버를 호출 할 수 없습니다. socket->thead()은 현재 스레드가 아니기 때문에 socket->moveToThread(this->thread()) 뒤에 함수 멤버를 호출 할 수 없습니다.

here에 설명되어 있습니다 :

이벤트 움직이는 물체는 단 하나의 스레드에서 사용할 수있다. 특히 타이머 메커니즘 및 네트워크 모듈에 적용됩니다. 예를 들어 타이머를 시작하거나 스레드의 객체가 아닌 스레드의 소켓을 연결할 수 없습니다. 이제

, 당신은 단지 TCP 소켓을 연결하려는 많은 것도 this에 대한 참조를 제거하고 그런 일 할 수 없습니다하는 경우에 당신은 당신의 코드를 해결하기 위해 무엇을 할 수 있는지 :

void MainWindow::checkCamStatus(){ 
    while(1){ 
     bool flag = false; 
     QScopedPointer<QTcpSocket> socket(new QTcpSocket()); 
     socket->connectToHost("10.0.7.112", 80); 
     if(socket->waitForConnected(1000))//check for connection for i second 
     { 
     qDebug() << "Cam online"; 
     } 
     else{ 
     qDebug() << "..............................Cam offline"; 
     } 

     QThread::sleep(1); 
    } 
} 

을하지만, ,

class CamWatcher : public QObject 
{ 
    Q_OBJECT 
public: 
    CamWatcher(QObject *parent = 0) : 
     QObject(parent), 
     m_socket(new QTcpSocket(this)) 
    {} 
    QTcpSocket *socket() { return m_socket; } 

public slots: 
    void tryConnect() { socket->connectToHost("10.0.7.112", 80); } 

private slots: 
    void onSocketConnected() { qDebug() << "Connected"; } 
    void onSocketDisconnected() { qDebug() << "Disconnected"; } 
    void onSocketError(QAbstractSocket::SocketError socketError) 
    { 
     qWarning() << m_socket->errorString(); 
    } 
private: 
    QTcpSocket *m_socket = nullptr; 
} 

이 방법은 모든 TCP 물건을 가질 수 있습니다 (모니터링 : 당신은, 데이터 송수신과 같은 TCP 소켓과 다른 뭔가를 수행하려는 경우, 당신은 클래스의 더 나은 포장까지 코드 것 데이터 t 전송 등)을 수행 할 수 있습니다. MainWindow와 동일한 스레드에서 사용할 수 있지만 필요한 경우 다른 스레드에서도 사용할 수 있습니다.

주 당신은 MainWindow를보다 다른 스레드에서 CamWatcher을 가지고 있지만, 당신은 같은 것을 할 필요가 CamWatcher의 기능을 호출 할 경우 :

QTimer::singleshot(0, camwatcher, &CamWatcher::tryConnect); 
QMetaObject::invokeMethod(camwatcher, "tryConnect", Qt::QueuedConnection); // No compile time check, works only with slots 
QMetaObject::invokeMethod(camwatcher, &CamWatcher::tryConnect, Qt::QueuedConnection); // Requires Qt 5.10 
1
QFuture<void> f2 = QtConcurrent::run(this,&MainWindow::checkCamStatus); 

QFuture는 다른 스레드에서 &MainWindow::checkCamStatus 함수를 실행합니다.

checkCamStatus 함수에서 새 소켓을 만들면 다른 스레드에서 발생합니다. checkCamStatus 함수 외부에 소켓을 만들어야합니다.

QTcpSocket* socket = new QTcpSocket(); // Remove the parent from here 
socket->moveToThread(this->thread()); // Move socket back to the original thread 
socket->setParent(this);    // Set socket's parent here, this and socket are now on the same thread 

을하지만 대체 솔루션이 덜 우아한 :

다른 방법은 다음과 같이 완전한 리팩토링을 피하기 위해 기존 코드를 수정할 수 있습니다. this->thread()은 현재 스레드 (QThread::currentThread())하지 않기 때문에, 당신은 new QTcpSocket(this)this을 사용할 수 없습니다

: 코드에 어떤 문제가 있는지

+2

실제 프로젝트에서는이 작업을 수행하지 마십시오. 스레드간에 qt 소켓을 이동하는 것은 안전하지 않습니다. –