2

serialPort を削除すると、デバッグ ビルドで次のメッセージが表示されます。

QCoreApplication::sendEvent での ASSERT エラー: 「別のスレッドが所有するオブジェクトにイベントを送信できません。現在のスレッド c0a528。レシーバー '' (タイプ 'QSerialPort') がスレッド c76850 で作成されました」、ファイル kernel\qcoreapplication.cpp、行 532

メイン ウィンドウを閉じると、~QSerialReader で実際のエラーが発生します。これがコードです。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    runnerThread=new QThread(this);    
    /*  - connect thread start signal to qrunnerthread's runLoop()
        this starts the main job loop            
        - connect thread finished signal to mainwindows' deleteLater
        to ensure proper deletion */
    qDataReader = new QDataReader();
    connect(runnerThread, SIGNAL(started()), qRunnerThread, SLOT(runLoop()));    
    connect(runnerThread, SIGNAL(finished()), this, SLOT(deleteLater()));
    qDataReader->moveToThread(runnerThread);
    runnerThread.start();
}

MainWindow::~MainWindow()
{
    runnerThread->exit();
}

//slot that runs when thread is started
void QDataReader::runLoop() {
    /* this code runs in different thread than QDataReader */    
    //serialPort parent will be QThread (runnerThread)
    serialReader=new QSerialReader(this);        

    while(doStuff) {    
        QString data=serialReader.readData();
        emit dataReceived(data);    
    }
}

QDataReader::~QDataReader() {
    delete runner;
}

QSerialReader::QSerialReader(QObject* parent) {
    //serialPort parent will be QSerialReader
    serialPort = new QSerialPort(this);
}

QSerialReader::~QSerialReader() {   

    /*
    deleting serialPort causes this message in debug builds:

    ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread c0a528. Receiver '' (of type 'QSerialPort') was created in thread c76850", file kernel\qcoreapplication.cpp, line 532
    */
    delete serialPort;  
}

edit1: ペッペの提案:

QSerialReader を QDataReader のメンバーに変更すると、問題はなくなります。しかし、QSerialPort::open でポートを開くと、次のエラーが表示されます。

QObject: 別のスレッドにある親の子を作成できません。(親は QSerialPort(0xdf6930)、親のスレッドは QThread(0xd8a528)、現在のスレッドは QThread(0xdf6850) QObject: 別のスレッドにある親の子を作成できません。(親は QSerialPort(0xdf6930)、親のスレッドは QThread です) (0xd8a528)、現在のスレッドは QThread(0xdf6850) です

QSerialPort::open(xx) は serialReader.readData() 内で呼び出されます。

それでも...厄介な問題があります。数年前に Java でコーディングしたときは、このような問題はありませんでした。

stack trace when CSerialReader::openPort is called. this calls QSerialPort::open. Clearly this is run in other thread than main.

0   CSerialReader::openPort serialreader.cpp    480 0xff7211    
1   CSerialReader::readData serialreader.cpp    209 0xff4e1d    
2   QDataReader::runLoop    qdatareader.cpp 138 0xffa3fe    
3   QDataReader::qt_static_metacall moc_qdatareader.cpp 62  0x1040824   
4   QMetaObject::activate   qobject.cpp 3539    0x669b0e14  
5   QThread::started    moc_qthread.cpp 113 0x66a29979  
6   QThreadPrivate::start   qthread_win.cpp 345 0x66816918  
7   _callthreadstartex  threadex.c  314 0xf71a293   
8   _threadstartex  threadex.c  297 0xf71a224   
9   BaseThreadInitThunk kernel32        0x74cd3677  
10  __RtlUserThreadStart    ntdll32     0x76f9c002  
11  _RtlUserThreadStart ntdll32     0x76f9bfd5  

CSerialReader が作成されたときのスタック トレース (メンバー変数として)。これはメインスレッドで呼び出されます。

0   CSerialReader::CSerialReader    Runner.cpp  48  0x9d3d14    
1   QDataReader::QDataReader    qdatareader.cpp 10  0x9d8fa4    
2   MainWindow::MainWindow  mainwindow.cpp  72  0x9c61eb    
3   main    main.cpp    105 0x9c4adc    
4   WinMain qtmain_win.cpp  131 0xa273ba    
5   __tmainCRTStartup   crtexe.c    547 0xa269e0    
6   WinMainCRTStartup   crtexe.c    371 0xa2676f    
7   BaseThreadInitThunk kernel32        0x74cd3677  
8   __RtlUserThreadStart    ntdll32     0x76f9c002  
9   _RtlUserThreadStart ntdll32     0x76f9bfd5  
4

1 に答える 1