2016-11-28 5 views
2

Qtでは、2つの異なるスレッドから同じシリアルポートを同時に読み書きすることはできますか?2つのスレッドを使ってシリアルポートを同時に読み書きする

+0

ありませんが、あなたはそれが誤りで最も可能性が高いです行う必要があると思わせるものは何でも。もちろん、データはどこからでも得ることができますが、 'QSerialPort'メソッドの呼び出しはすべて' port-> thread() 'と同じスレッドから行わなければなりません。 –

+0

@Kuba Ober、私はあなたを得る。しかし、ここに問題があります。あるスレッドでシリアルポートを読み取ってGUIスレッドで表示することをデモしようとしています。これをテストするために、私はシリアルポートに連続的に書き込む必要があり、同時に同じデータをシリアルポートから読み込んでGUIスレッドに表示する必要があります。そして、私はこれをすべて一つのマシン(私のラップトップ)で実証しようとしています。だから私は私のアプリケーションで3スレッドを持つことを考えた。 1つのメインGUIスレッド、1つのリーダースレッド、1つのライタースレッド。 – Aham

+0

リーダーとライターは同じスレッドでなければなりません。シリアルポートの速度がCPU /メモリの帯域幅と比較して相対的に遅いことを考えると、ジョブを2つのスレッドに分割すると、パフォーマンスは悪くなく良くなります。複数のスレッドを持つオーバーヘッドは、シリアルポートを詰め込むいつでもデータを持ち、返答を処理することができます。 –

答えて

1

インプリメンテーションのために異なるスレッドから読み書きすることはできません(QtのI/Oクラスと同じ)。 QSPは、非同期(非同期)I/Oを使用します。これにより、1つのスレッドからの読み込み/書き込みを「同時」に使用できます。

2

直接ではありません。 portで呼び出すメソッドは、port.thread()の範囲内で呼び出す必要があります。そうでない場合は、未定義の動作です。ハードドライブをフォーマットすることができます。

しかし、シグナルスロットメカニズムを使用して間接的に行うことができます。代わりに、ポート上のメソッドを呼び出す、のは、ポートにスレッドセーフなインターフェースとして動作するインタフェースクラスを持ってみましょう:

struct PortInterface : QObject { 
    Q_SIGNAL void writeData(const QByteArray &); 
    Q_SIGNAL void hasReadData(const QByteArray &); 
    Q_OBJECT 
}; 

int main(int argc, char ** argv) { 
    QApplication app(argc, argv); 
    PortInterface interface; 
    QSerialPort port; 

    QObject::connect(&interface, &PortInterface::writeData, &port, [&](const QByteArray &data){ 
    qDebug() << "writing in thread" << QThread::currentThread(); 
    Q_ASSERT(QThread::currentThread() == port.thread()); 
    port.write(data); 
    }); 
    QObject::connect(&port, &QIODevice::readyRead, [&]{ 
    qDebug() << "reading in thread" << QThread::currentThread(); 
    Q_ASSERT(QThread::currentThread() == port.thread()); 
    emit interface.hasReadData(port.readAll()); 
    }); 

あなたが任意のスレッドでwriteDataメソッドを呼び出すことができます。Qtのシグナル・スロット機構でラップしますコールを安全にポートのスレッドに配信します。同様に、hasReadDataシグナルはどのスレッドからでも呼び出すことができます。 readAll呼び出しは、ポート自身のスレッドから実行されます。利用可能なデータを処理するコードは、そのスロットに接続する必要があります。

したがって、我々はポートにいくつかのデータを書き込むために、専用のスレッドでティックタイマーを持つことができ、我々はメインスレッド内の新しいデータに耳を傾けスロットを持つことができます。

QTimer sourceTimer; 
    sourceTimer.start(20); 
    QObject::connect(&sourceTimer, &QTimer::timeout, [&]{ 
    qDebug() << "timer tick in thread" << QThread::currentThread(); 
    interface.writeData(QByteArray(20, 'd')); 
    }); 
    QObject::connect(&interface, &PortInterface::hasReadData, &app, [&](const QByteArray &data){ 
    qDebug() << "data read in thread" << QThread::currentThread(); 
    qDebug() << data.toHex(); 
    }); 

    QThread sourceThread, portThread; 
    QThread::currentThread()->setObjectName("mainThread"); 
    sourceThread.setObjectName("sourceThread"); 
    portThread.setObjectName("portThread");; 
    sourceTimer.moveToThread(&sourceThread); 
    port.moveToThread(&portThread); 
    sourceThread.start(); 
    portThread.start(); 
    return app.exec(); 
} 

あなたはすることができます任意の数のオブジェクトをhasReadData信号に添付します。これらのオブジェクトはどのスレッドにも存在できます。信号スロット接続は1:n種類であることを思い出してください。ここでは0<=nです。

同様に、インターフェイスのwriteDataメソッドを呼び出すオブジェクトはいくつでもかまいません。書き込むデータが自己完結型パケットであれば、パケットがポートに送信されることが保証されます他のパケットとインターリーブすることはありません。しかしながら、受信機はパケットを描写することができなければならない。パケットはヘッダまたは他の同期手段(例えばHDLC)を必要とする。

あなたが最初のポートを開く必要があります。もちろん、

:)

+0

Qtプロジェクトにこのコードを手配してもらえますか?上記のコードのどこに行くのか? – Aham

+0

@Aham散文(説明文)がそこになかったと想像してください。コードフラグメントを貼り合わせると、コンパイルできる 'main.cpp'が得られます。ポートが開いていないのであまり役に立ちませんが、それ以外は完全です。 –

関連する問題