マルチスレッドIODEVICEを使用してQtの分析

入門

 QThreadと弟を参照するにはこれらの二日間は、子スレッドがグループ内のシリアルデータコードを読み取る作成します。

void myThread::run()
{
	...
	QThread::msleep(100);
	m_port->waitForReadyRead(10);
	ret= m_port->read(buf,len);
	...
}

 私はまた、シリアル読み取りと書き込みのコードを書いたが、無駄にwaitForReadyReadこの機能を。私はなぜ、このようなブロック機能を追加し、私は追加していない、この機能の使用は何である彼に尋ねたああ正常に読み、そしてあなたはQThreadの上に追加することができます:: msleep(100)。私の弟が初心者で、彼は現象は、この機能せず、次の読み出したデータを読み取ることができないと教えてくれましたが、なぜ、彼は知りません。
 おそらくこれが今問題の原因である、私は私が読んで、コードはメインスレッドで実装されている書き込みと思うし、そのコードは、クロススレッドです。

コード

 なしでシミュレートの下に書かれたそのコードに応じて、一般的に私はそうwaitForReadyReadこの状況。

mythread.h myThreadクラスの(子スレッド)

class myThread : public QThread
{
public:
    myThread();
    void run();
    QSerialPort *m_serial;
};

mythread.cpp

myThread::myThread()
{
    m_serial = new QSerialPort;
    if (false == m_serial->isOpen())
    {
        m_serial->setPortName("COM6");
        m_serial->setBaudRate(QSerialPort::Baud9600);
        m_serial->setDataBits(QSerialPort::Data8);
        m_serial->setParity(QSerialPort::NoParity);
        m_serial->setStopBits(QSerialPort::OneStop);
        m_serial->setFlowControl(QSerialPort::NoFlowControl);
        m_serial ->open(QIODevice::ReadWrite);
    }
}
void myThread::run()
{
	...
	int wcount = m_serial->write(cmd);
	QTimer::singleShot(1000, this, [=](){
        qDebug()<<"usableSize = "<<m_serial->bytesAvailable();
        const QByteArray data = m_serial->readAll();
        qDebug()<<"dataSize = "<<data.size()<<m_serial->bytesAvailable();
    });
	
}

mainwindow.cppコンストラクタ

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_myThread = new myThread();
    m_myThread->start();
}

コード説明

 宇宙の理由は、全体のコードが掲載され、簡単に紹介されていません。
メインスレッドは、(GUIスレッド)スレッドは、子インスタンスを作成し、サブスレッドコンストラクタは、シリアルオブジェクトと子スレッドが(すなわち、スタート機能)を実行する初期化シリアル読み出しと書き込みを行います。

疑問プロセス

 私が読むにデータが存在しない、上記のコードを実行します。

	int wcount = m_serial->write(cmd);
	QTimer::singleShot(1000, this, [=](){
        qDebug()<<"usableSize = "<<m_serial->bytesAvailable();
        const QByteArray data = m_serial->readAll();
        qDebug()<<"dataSize = "<<data.size()<<m_serial->bytesAvailable();
    });

 実行の結果として、

	usableSize =  0
	dataSize =  0 0

そして、出力、警報などの印刷ルックスを持っていますが、プログラムの動作に影響を与えていないようです
QObject: Cannot create children for a parent that is in a different thread. (Parent is QSerialPort(0x20c23a80), parent's thread is QThread(0x846fb0), current thread is QThread(0x20c239c0)

 私は一時的に関わらず、警告のこちらを選択します。
 非常に奇妙な、私はシリアルポートの1秒にコマンドを記述した後、実際に返されたデータを読んでいません。メインスレッドで同じ文言は、シリアルポートパラメータに従って、唯一未満百ミリ秒を正確にすべてのデータを受信することができます。
 私は2秒5秒までの時間1秒に延長されますので、我々は関係なく、任意のデータを受信することはできませんどのくらい、その変化は認められませんでした。
 書き込みコマンドの後に追加私はそうwaitForReadyReadの機能と、それは本当にデータを読み取ることができますが、データは多くの場合、間違っていることがわかりました。
 だから、私は書類を確認し、

このようQTcpSocketやQProcessなどのQIODeviceの特定のサブクラスは、非同期です。コントロールバックイベントループになると、デバイス自体との通信が起こるかもしれないが、常に、直ちに戻す)ような書き込みなどのI / O関数は、()または(読み取り、この手段。

いくつかのQIODeviceサブクラス(例えばQTcpSocketとザQProcess)は非同期です。このようなI / O機能として、このような書き込みなどの手段、()または読み取り()が常にすぐに戻り、イベントループに戻って、通信装置自身が発生することがあります。

 ように、IODEVICEは(シリアルポートを含める必要があります)いくつかのサブクラスは、読み込みと書き込み操作は非同期です私はすぐにデバイスに書き込まれていない書き込みの後で、イベントループで戻りする可能性があること、唯一の本物のデータが書かれています。この点について検証することができる機能があり、

	/* 我这边cmd长度是10 */
	int wcount = m_serial->write(cmd);
	/* bytesToWrite,返回等待写入的字节数 */
	qDebug()<<"wcount"<<wcount<<"writebuff"<<m_serial->bytesToWrite();

実行出力がwcount 10 writebuff 10、あなたは、バイト数が書かれており、機器が、現時点ではそれが存在する場所cmdを一切書き込みデバイスは、私が文書をレビューしていないと明確に述べられないことが判明していることを示す、10であることを待っているバイト数を書き込むために見ることができますしかし、打ち上げ缶何かデバイスとQSerialPortの間には、バッファ(バッファ)があります
 だから、場合に私waitForReadyReadは、機能をブロックすることなく、タイマーの前にスロット内の機能も追加されたデータ読み取りに接続bytesToWriteの、印刷を

	QTimer::singleShot(1000, this, [=](){
        qDebug()<<"usableSize = "<<m_serial->bytesAvailable()<<m_serial->bytesToWrite();
        const QByteArray data = m_serial->readAll();
        qDebug()<<"dataSize2 = "<<data.size()<<m_serial->bytesAvailable();
    });

驚くべきことは、起こった実際に、それは、データバッファに残っており、デバイスに書き込まれていませんm_serial->値bytesToWrite()または10
 この時点で、私は非常に明らかに書き込みを呼び出して、混乱していますが、実際には、スレッドの終了時にシリアルデバイスへのデータの書き込みをしませんでした。押して文書は、前記イベントループに戻るが、装置と通信自体が発生する可能性が場合ように、イベントループ、スレッド終了、スレッドの警告の始まりは、突然、より多くの未知のものは、私が思うに、私はイベントスレッドの終わりとから子糸ループの検索から開始する必要があります。
 案の定、私たちは、QThreadからのイベントループについて何かを見つけました

デフォルトでは、実行()は(幹部を呼び出してイベントループを開始します)、スレッド内のQtのイベントループを実行します。

実行関数が戻った後にスレッドが終了します。あなたは()execを呼び出さない限りスレッドで実行されている任意のイベントループがあってはなりません。

デフォルトでは、実行()イベントループを実行するために()execを呼び出します。それ以外の場合は、スレッドの終了後に、機能のリターンを実行し、子スレッドにはイベントループはありません。
 言い換えれば、私のコードは、デフォルトの実行を無効にmyThreadで実行され、私はイベントループを実行するためのexecを持っていません。だから、子スレッドが終了するまで、また、独自のイベントループなので、非同期書き込みやデバイスにデータを書き込むことが最終的にできませんすることに失敗しました。
 だから、私はデータを読み、私のexec()プロモーターのスレッドのイベントループの最後に追加オーバーロードラン()、そして必ず十分に試してみました。
 この時点で私は、振り返って、waitForReadyRead上のドキュメントを確認します

[仮想] BOOLのQIODevice :: waitForReadyRead(int型のミリ秒)
この関数はイベントループなしで動作することができます。これは、非GUIアプリケーションを作成する際に有用であり、非GUIスレッドでI / O操作を実行するとき。
readyRead()信号に接続されたスロット内から呼び出された場合、readyRead()が再放出されないであろう。
カスタムデバイスのためのブロッキングAPIを提供するために、この関数を再実装してください。デフォルトの実装では何もせず、falseを返します。
警告:メイン(GUI)スレッドからこの関数を呼び出すと、ユーザーインターフェイスがフリーズすることがあります。

 だから、私はあなたがこの機能は、状況の無いイベントループであり、使用することをお勧め
してものQIODeviceの導入で見ることができ、

このようQTcpSocketやQProcessなどのQIODeviceの特定のサブクラスは、非同期です。コントロールバックイベントループになると、デバイス自体との通信が起こるかもしれないが、常に、直ちに戻す)ような書き込みなどのI / O関数は、()または(読み取り、この手段。QIODeviceは、あなたが呼び出し元のスレッドをブロックし、イベントループに入らずながら、すぐに実行されるように、これらの操作を強制できるようにする機能を提供します。これは、のQIODeviceのサブクラスはイベントループなしで、または別のスレッドで使用することができ:
waitForReadyRead() -呼び出したスレッドにこの機能を一時停止操作新しいデータが読み出しのために利用可能になるまで。
waitForBytesWritten() -呼び出したスレッドにこの機能を一時停止操作データのペイロードは、デバイスに書き込まれるまで。
waitFor ...() - のQIODeviceのサブクラスは、デバイス固有の動作のための機能をブロック実装。例えば、QProcessは、プロセスが開始されるまで呼び出しスレッドで動作を停止waitForStarted(と呼ばれる機能)を持っています。

一連の機能WAITFOR、スレッドがブロックされ、同期を達成。

再解析

 実際には、このポイントに、冒頭でwaitForReadyReadの問題結果を実行するために、同じ日数を書くのメインスレッド別の問題である説明されています。しかし、文言上のそこwaitForReadyReadは問題があることが多いデータの警告をお読みください。だから私は、これら2つの点を調査し続けました。

警告

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0x20c23a80), parent's thread is QThread(0x846fb0), current thread is QThread(0x20c239c0)

 大雑把にそれは私が別のスレッドで、このような子オブジェクトとその親オブジェクトの子オブジェクトを作成できないことを意味します。
 印刷位置することにより、Iすばやく移動するには、次のコードフレーズ警告が生じ、

    int wcount = m_serial->write(cmd);

 まず第一には、オブジェクトを作成するがある場合、このコードは、明示的にも書き込み内部実行に続いてオブジェクトを作成しない、そうではありません、そして同じスレッドでm_serialシリアル・オブジェクト?
 疑問で、私は、元の文書、この調査、驚きを開設しました

親スレッドの所有権QThreadオブジェクト。

 子スレッドオブジェクトはメインスレッドに属しているので、他の言葉では、私は、メインスレッドが作成された子スレッドです。子スレッドオブジェクトは、メインスレッドに属し、サブスレッドのその後のメンバー、メインスレッドに属しているので。だから、m_serialシリアル・オブジェクトは、実際には、メインスレッドに存在し、私の操作は、クロススレッドでの動作です。
 また、検査FOUND

QThread ::実行するには、()、それは子スレッドの一部であるものを作成し、全体のサブスレッドのエントリです。

 この私はまた、コンストラクタサブスレッド内のスレッドの数、スレッド数で印刷され、様々なオブジェクトを印刷すると決定印刷スレッド番号を実行します。
 それはそう、シリアル書き込みが実現すれば、実際のオブジェクト、ケースを作成することですので、警告が表示され、オブジェクトの異なる部分が異なるスレッドに位置していると述べました。
 OK、誰がこの警告にも非常に簡単です解消したい、シリアルポートオブジェクトは、実行中に作成されるようにすることです、または書き込みは子スレッド(実行)の呼び出しではありません。
 ああ、ここmyThreadオブジェクト自身が親スレッド、QTimerの一部ですので、私は、問題を発見:: SINGLESHOT()信号を送信するために、受信者はSINGLESHOT()がタンクに接続されていること、糸自体の関数であること、これであります実行は、オブジェクトの親スレッドではないでしょうか?または親スレッドで実行しません。
 印刷検証、案の定、印刷または親スレッドでスレッドスロットによります。言い換えれば、私はだから今、子スレッドが不完全書き込み、または書き込みを実行し、他のものは、親スレッドです。
 ここで、私はQtのを使用するために私の全スレッドを感じ、それが問題です。
 オンライン検索の詳細については、Qtは非常に徹底した記事で、この領域でのマルチスレッド化のために使用した、
ポータル
 の使用への彼の非常に単純な、一般的なQObjectの派生クラスの定義をした後、QThread内のオブジェクトに移動します。シグナルとスロットを使用するときに複数のスレッドが存在して検討する必要はありません。同期するためにQMutexを使用しないでください、Qtの独自のイベントループは、これを自動的に処理します。(理由で、別のスレッドでそれらのオブジェクトと送信信号の対象スロット、デフォルトの接続タイプはqueneConnectある、即ちスロット機能はスレッドで実行されるオブジェクトが属する受信すると、ここで、使用は太字であることができます)
 珍しいを読み出したデータのためとして、私は私が運転中のスレッドを読んだとき、そこにいないので、クロススレッド操作は、不確実性にはつながらないと思いをハザード。

概要

  1. 多くのIODEVICEサブクラス読み取りおよび書き込み操作は非同期です。
  2. waitForReadyReadは、同期効果を達成するためにスレッドをブロックする(しかし、GUIスレッドがGUIをブロックする、インターフェイスが貼り付け)
  3. 子スレッドが過負荷時にイベントループ処理の注意
  4. 対象サブスレッドオブジェクトとオブジェクトのメンバーは、親スレッドに属しています
  5. クロススレッド操作のQIODeviceは、クラスは関連しないでください
  6. Qtは、使用するマルチスレッド共通QObjectのクラスを派生し、その後QThreadでオブジェクトを移動させるように定義します。シグナルとスロットを使用するときに複数のスレッドが存在して検討する必要はありません。同期するためにQMutexを使用しないでください、Qtの独自のイベントループは、これを自動的に処理します。
公開された60元の記事 ウォン称賛18 ビュー20000 +

おすすめ

転載: blog.csdn.net/BadAyase/article/details/103695081