3

別のスレッドからシグナルを発信しようとすると、セグメンテーション違反が発生しますが、理由はわかりません。
シグナルとスロットはどちらも同じクラスで定義され、メインの GUI スレッドで実行されますが、ブースト スレッド タイプのスレッドによって制御される別の関数で発行を呼び出します。

私は Qt4 を使用しており、Ubuntu 10.04 が私の OS です。この関数は、シグナルを発信している別のスレッドから呼び出されます。

    void MyMapItem::updateMap(std::vector<int> data11)
{
my_mutex.lock();    
cout<< "i am in updatemap"<<endl;
data12.clear();
data12=data11;
cout<<"size of data"<<data12.size()<<endl;
my_mutex.unlock();
emit mera_signal();
}

    MyMapItem::MyMapItem(QGraphicsItem *parent )
{

    QObject::connect(this,SIGNAL(mera_signal()),this,SLOT(mera_slot()),Qt::BlockingQueuedConnection );



}

上記は私のQtクラスのコンストラクタです。

void MyMapItem::mera_slot()
{
cout<< "signal is emitted"<<endl;
qDebug() << "Date:";
} 

上記はスロットの定義です。とりあえずメッセージを出力しています。

流れをもう少し詳しく説明します。

  1. ROS に接続され、トピックにサブスクライブする、今 MapGeneratorから継承されるクラスが 1 つあります。QThread
  2. ここで、両方MyMapitemから継承された別のクラスを取得し、このクラスでスロットとシグナルを定義しました。 QObjectGraphicsItem
  3. Mainwindowから継承された 3 番目のクラスを取得Qobjectし、グラフィックス シーンをセットアップしますmymapitem
  4. ここで私がやってmainいることは、オブジェクトを作成Mapgeneratorしてスレッドを開始することです。
  5. 次に、 のオブジェクトを作成しますMainwindow
  6. そのため、Mapgeneratorスレッドが開始すると、ROS からデータをサブスクライブし、関数を呼び出してMyMapItemそこにデータを転送します。

ここでは、新しいデータが到着したことを知るために信号を送信したいと考えています。Mainwindow次に、コンストラクターで既にシーンにあるアイテムを更新します。接続はMyMapItemクラス コンストラクターで行われます。

ありがとう ここにスレッドとメインウィンドウを作成しているメインメソッドを投稿します。

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ros::init(argc,argv,"last");
    MapGenerator::MapGenerator mg(argc,argv);
    //boost::thread ros_thread(boost::bind(&MapGenerator::init2, &mg));
    mg.start(); // Qthread 
    MainWindow w(argc,argv);
    w.show();
    return a.exec();
}

ここでメインウィンドウコンストラクターで Mapitem オブジェクトを作成しました

MainWindow::MainWindow( int argc, char **argv, QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowTitle("My app");
    mapitem = new MyMapItem();
    scene = new QGraphicsScene(0,0,4000,4000);
    ui->graphicsView->setScene(scene);
    scene->addItem(mapitem);
}
4

4 に答える 4

2

connect多くの場合、スロットへの信号を含むクラスを設定する場合、接続タイプを指定するオプションがあります。

bool QObject::connect ( const QObject * sender, const char * signal,
const QObject * receiver, const char * method,
Qt::ConnectionType type = Qt::AutoConnection ) [静的]
________________ <--- 接続タイプを次のように指定しますキューに入れられたものの1つ

デフォルト値は、シグナルが同じスレッドから来ているか、別のスレッドから来ているかを知るためのものにQt::AutoConnection依存しています。QThreadQThreads を使用していないため、これに頼ることはできません。呼び出しスレッドでの動作方法に応じて、QueuedConnectionまたはそれに応じて接続を確立するように明示的に指示します (詳細については、リンクを参照してください)。BlockingQueuedConnection

何らかの理由で接続を常にこれらのタイプのいずれかに設定することが不適切である場合は、QMetaObject::invokeMethodを使用して別のスレッドから呼び出すこともできます。この関数では、接続タイプも指定できることに注意してください。

オブジェクト obj のメンバー (シグナルまたはスロット名) を呼び出します。メンバーを呼び出すことができた場合は true を返します。そのようなメンバーが存在しない場合、またはパラメーターが一致しなかった場合は、false を返します。呼び出しは、タイプに応じて、同期または非同期のいずれかになります。

タイプが Qt::DirectConnection の場合、メンバーはすぐに呼び出されます。

type が Qt::QueuedConnection の場合、QEvent が送信され、アプリケーションがメイン イベント ループに入るとすぐにメンバーが呼び出されます。

type が Qt::BlockingQueuedConnection の場合、メソッドは Qt::QueuedConnection と同じ方法で呼び出されますが、イベントが配信されるまで現在のスレッドがブロックされる点が異なります。この接続タイプを使用して同じスレッド内のオブジェクト間で通信すると、デッドロックが発生します。

type が Qt::AutoConnection の場合、obj が呼び出し元と同じスレッドにある場合、メンバーは同期的に呼び出されます。それ以外の場合は、メンバーを非同期的に呼び出します。

于 2012-07-13T20:16:05.843 に答える
1

ブースト スレッド タイプのスレッドによって制御されています。

QT のシグナルは、QT のシグナルとスロットに関連付けられた QObject に関するあらゆる種類のメタデータを認識している QObject に実装されています。これらのメタデータの 1 つがスロットの QObject に関連付けられた QThread で、スロットがシグナルに対してどのように呼び出されるか (つまり、同じスレッド内で、別の QThread にポストされるなど) のデフォルトの動作を決定します。

これがブーストなどの他のスレッド ライブラリでうまく機能するかどうかは疑わしいです。シグナル/スロットを接続するときにQObjectがスロットのQObjectが2番目のスレッドに関連付けられていることさえ知らないことはかなり確実です。アプリケーションのメイン QThread に誤って関連付けられる可能性があります。

オブジェクトをスレッドに関連付けることは、他のスレッド API と比較して QT の優れた機能です。QTが別のライブラリでスレッドを作成していることを自動的に認識し、QTがスレッド、シグナル、およびスロットをスレッドセーフにする方法で理解できるように、スレッドをQObjectに感覚的に関連付けることができる可能性はほとんどありません。 .

「スレッドと QObjects」の QT ドキュメントで詳細をお読みください。

于 2012-07-13T18:34:00.393 に答える
0

私は最近同じ問題を経験しました。正常に動作している従属 GUI スレッドからサブプロセスを介してシェル コマンドを呼び出すことがかなりありますが、正しく動作することを拒否して segfault が発生します。私が到達した違いは、メインの GUI スレッドから実行しようとしていて、通常はサブスレッドから発行されるシグナルを発行しようとしたときにセグメンテーション違反が発生したという事実にあります!

セグメンテーション違反を回避するための私の解決策は、シェルの関与が必要なダイアログの部分を別の QThread に移動し、アプリ内の他のスレッドが使用しているのと同じ共通クラスを効果的に継承することでした。問題はなくなりました!QThread が鍵です!

ここで完全な回答を参照してください: https://stackoverflow.com/a/13978817/673423

于 2012-12-20T19:41:39.973 に答える
0

ブロッキングキューシグナルを使用する必要があります。Qt には、Qt::BlockingQueuedConnection で接続を定義する QThreads にこの機能があります。ブーストスレッドについてはわかりません。

于 2012-07-13T18:56:07.863 に答える