QT,在A线程中循环创建N个B线程,经测试,这N个B线程执行完毕之后不会发送finished信号,程序也不会析构它们,何解?

hookover 发布于 2014/07/20 19:55
阅读 1K+
收藏 2
Qt
QT,在A线程中循环创建N个B线程,经测试
这N个B线程执行完毕之后不会发送finished信号,程序也不会析构它们,何解?

下面用伪代码表示吧,代码可能不对,但我做的程序是想这样来实现的

先构建两个线程

A class:public QThread{
public:
   A:A(){
            //BThread=new B;           //将run()函数中的new B移动到这里来,B执行完就会正确析构
    }
     void run(){
             while(true){
                    BThread=new B;
                    connect(BThread,SIGNAL(finished()),BThread,SLOT(deletelater()));
                    BThread->start();
             }
      }
private:
     B *BThread;
}
B class:public QThread{
public:
      void run()
      {
               qDebug()<<currentThreadId();
               this->exec();   //写不写都一样
               this->quit();     //写不写都一样
       }
}
 
main{
  A *a=new A;
 a->start();
}


我想实现的功能是:
A线程的run函数中不断new出来B线程对像
             while(true){
                    BThread=new B;
                    BThread->start();
                    connect(BThread,SIGNAL(finished()),BThread,SLOT(deletelater()));
             }

当B线程对像执行完之后,会自动析构
但是我这种做法,它是不会自动析构的
-----------------------------------------
另外我尝试在A线程中创建QVector<B> *BVector 
然后将A中创建的B线程对像放到BVector中,然后再forech这些对像,发现它们都在运行,没有结束
强制delete会告诉我这些对像在运行,BVector->item-isfinished()  发现它还在运行
也就是在A中创建的B线程对像执行start(),run()函数中的内容运行完之后,它不退出

————————————————————————————————————————

已经Google/百度搜索多次,没有发现我想实现的这种样例和解决方法
请高手帮我改一下,改成它能够自动析构,
并且我可以随意创建N个B线程对像并执行

希望各位大大,建一个这样的工程,然后测试一下,给一份可行的代码给我
非常感谢!

加载中
0
纵使有花兼明月何堪无酒亦无人
纵使有花兼明月何堪无酒亦无人
while(true)
{//开始
     B  b=new B();//这样每次都创建B  结束了就自动析构了他的范围也是在开始和结束的那个大括号里
     b->start();
}//结束



hookover
hookover
这样做不行的,你的意思是 B b; <-这样定义吧 B b=new B()是错误的 B *b=new B()是正确的 因为线程还要执行一阵 但是while循环的时间非常快, 线程还没执行完,while就结束了,b对像就不见了,程序会崩溃
0
hehuim
hehuim

你的B与A在一个线程中吧!

现在已经不建议在run中写了,直接用QObject::moveToThread,QThread也继承自QObject,也可以这么用!我觉得你可能需要看下面的这段,Qthread的文档里的

It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.
When subclassing QThread, keep in mind that the constructor executes in the old thread while run() executes in the new thread. If a member variable is accessed from both functions, then the variable is accessed from two different threads. Check that it is safe to do so.

hookover
hookover
不过在我之前这样做的程序里面,我尝试过moveTOThread也不行,估计是在while里面导致的
hookover
hookover
多谢哥们,非常感谢,看来我要改变以前的思路了
0
渡世白玉
渡世白玉

this->exec();   //写不写都一样

这句是在县城开启事件循环、、、加上这句线程他就不会退出的、、

0
渡世白玉
渡世白玉

你的这个问题和线程没有关系的,线程是确定执行完毕推出的、、

只是资源释放的问题是在deletelater这儿的、、每个线程在Qt5中是一个独立的事件循环的,而这样执行,在这个线程里是没有事件循环,不知道这个和事件循环的关系很大,具体哪儿出问题了,我对Qt的事件循环还在研究中,不能给你解答,但是finished信号是确定发出去的,线程也是执行完毕了,只是为什么没有调用B的析构函数我就不大清楚了、、

附上我的代码:

A.h

#ifndef A_H
#define A_H

#include <QThread>

class A : public QThread
{
    Q_OBJECT
public:
    explicit A(QObject *parent = 0);

signals:

public slots:

protected:
    void run();
};

#endif // A_H
A.cpp

#include "a.h"
#include "b.h"
#include <QDebug>

A::A(QObject *parent) :
    QThread(parent)
{
}

void A::run()
{
    for (int i = 0 ; i < 10 ; ++i)
    {
        B* b = new B;
        connect(b,&B::finished,[](){
            QThread * b = QThread::currentThread();
//            if (b->isRunning()) b->quit();
//            b->wait(30); delete b;
            qDebug() << "isFinished" << b->isFinished();
            qDebug() << "isRunning" <<  b->isRunning();
        });
        connect(b,&B::finished,b,&B::deleteLater);
        b->start();
    }
    qDebug() << "??";
}
B.h

#ifndef B_H
#define B_H

#include <QThread>

class B : public QThread
{
    Q_OBJECT
public:
    explicit B(QObject *parent = 0);
    ~B();
signals:

public slots:

protected:
    void run();
};

#endif // B_H
B.cpp

#include "b.h"
#include <QDebug>

B::B(QObject *parent) :
    QThread(parent)
{
    connect(this,&B::finished,[](){qDebug() << "B::finished";});
}

B::~B()
{
    qDebug() << "~B : " << QThread::currentThreadId();
}

void B::run()
{
    qDebug() << "RUN : " << QThread::currentThreadId();
}
main.cpp

#include <QCoreApplication>
#include "a.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    A aa;
    aa.start();

    return a.exec();
}
至于输出,你就自己运行吧,注意需要Qt5,因为用的新信号槽的链接方法。

需要C++11编译器,里面有lambda表达式。

用GCC,自己在pro文件里加上:CONFIG   += C++11

渡世白玉
渡世白玉
回复 @暴牛软件 : 不神奇,你还是不了解QThread类,继承自QThread类实现的所谓线程类只是run函数里的部分在新线程执行,类的其他函数都是在旧线程执行的、、、
hookover
hookover
是不是在while内,构建的对你,必须等while结束,才能删除
hookover
hookover
~B : 0x9d0 ~B : 0x9d0 ~B : 0x9d0 ~B : 0x9d0 ~B : 0x9d0 ~B : 0x9d0 ~B : 0x9d0 ~B : 0x9d0 ~B : 0x9d0 ~B : 0x9d0 运行结果很神奇
hookover
hookover
白玉你好, 我想请教一下,A线程使用while循环可以吗?我是希望它一直运行,不停下来,我用信号和槽,来控制变量,使它不断的启动新的线程,释放旧的线程
0
danielgong
danielgong

A.h的run方法里加入exec(), 在A线程里开启事件循环,用来响应信号槽。

a.h

#ifndef A_H
#define A_H

#include <QThread>
#include <QVector>
#include "b.h"

class A : public QThread
{
    Q_OBJECT
public:
    explicit A(QObject *parent = 0);

signals:

public slots:

protected:
    void run();

private:
    B *b;
};

#endif // A_H
a.cpp

#include "a.h"
#include <QDebug>

A::A(QObject *parent) :
    QThread(parent)
{

}

void A::run()
{
    for (int index = 0 ; index < 100 ; ++index)
    {
        b = new B(NULL, index);
        connect(b, SIGNAL(finished()), b, SLOT(deleteLater()));
        b->start();
    }
    qDebug() << "??";
    exec();
}

b.h

#ifndef B_H
#define B_H

#include <QThread>
class B : public QThread
{
    Q_OBJECT
public:
    explicit B(QObject *parent = 0, int idx = 0);
    ~B();
    
signals:
    
public slots:

protected:
    void run();

private:
    int index;
};

#endif // B_H
b.cpp

#include "b.h"
#include <QDebug>

B::B(QObject *parent, int idx) :
    QThread(parent)
{
    index = idx;
}

B::~B()
{
    qDebug() << "~B : " << " index:" << index;
}

void B::run()
{
    qDebug() << "RUN : " << " index:" << index;
}
main.cpp

#include <QtCore/QCoreApplication>
#include "a.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    A aa;
    aa.start();
    return a.exec();
}
xxx.pro

#-------------------------------------------------
#
# Project created by QtCreator 2014-07-21T10:41:14
#
#-------------------------------------------------

QT       += core

QT       -= gui

TARGET = test111
CONFIG   += console
CONFIG   -= app_bundle

TEMPLATE = app


SOURCES += main.cpp \
    a.cpp \
    b.cpp

HEADERS += \
    a.h \
    b.h



hookover
hookover
回复 @danielgong : 朋友,非常感谢
danielgong
danielgong
回复 @暴牛软件 : 因为finished信号,thread已经结束,返回的是主线程ID,建议你使用线程池或QFuture异步线程
danielgong
danielgong
回复 @暴牛软件 : 因为析构时,线程已经执行完了,RUNNING is false, 返回的是主线程的ID
hookover
hookover
测试析构时返的线程ID都是一样的,不懂
hookover
hookover
danielgone你好, 我想请教一下,A线程使用while循环可以吗?我是希望它一直运行,不停下来,我用信号和槽,来控制变量,使它不断的启动新的线程,释放旧的线程
0
hookover
hookover

感谢上面几位大牛的帮助,经过你们的代码,我大概理解了在while里面创建的对像应该是不好停下来的。

我现在将new对象的操作放到槽函数中,好像就OK了,正确析构……

希望有其它大牛提出更好的办法解决这个问题:


A::A(QObject *parent) :
    QThread(parent)
{
    connect(this,SIGNAL(signal_run()),this,SLOT(slot_run()));
}

void A::run()
{
    int i=0;
    while(true)
    {
        if(i<10)
        {
            emit signal_run();
            i++;
        }
    }
}

void A::slot_run()
{
    B* b = new B;
    connect(b,SIGNAL(finished()),b,SLOT(deleteLater()));
    b->start();
}






hookover
hookover
回复 @渡世白玉 : 唉,我是新手,差劲得要命,但是经过实验,这样,B线程会自动析构……
渡世白玉
渡世白玉
惨不忍赌的代码、、 毫无意义的空县城、、你的slot_run还是在你新建A的那个线程执行的,并不是在新线程执行的、、
0
渡世白玉
渡世白玉
Qt有强大的事件循环呢、、
在run里面用while(true)就是错了、、这会让线程一直处于忙碌状态的,怎么有空处理你的信号操、、
最好直接用movetothread的、、继承自QThread的线程类只有run里才在新线程处理的、、

还有,Qt的线程类不单单只有QThread的、、你的需求u用线程池更好的,自己不断的开启,关闭线程,只会增加多余的消耗的、、

自己去看下:

QThreadPool和

QRunnable吧


hookover
hookover
好的,非常感谢白玉,你在其它地方也帮我我很多忙,嘿嘿
0
danielgong
danielgong
#include<QThreadPool>
#include<QDebug>

class A : public QRunnable
{
public:
    explicit A()
    {
    }
    ~A()
    {
        qDebug() << "~A " << QThread::currentThreadId();
    }
public:
    void run()
    {
        qDebug() << "Run A " << QThread::currentThreadId();
    }
};

int main()
{
    QThreadPool* threadPool = QThreadPool::globalInstance();
    qDebug() << "active thread: " << threadPool->activeThreadCount();
    qDebug() << "expire time out: " << threadPool->expiryTimeout();
    qDebug() << "max thread count: " << threadPool->maxThreadCount();
    for(int i = 0; i < 10; ++i)
    {
        A *a = new A;
        threadPool->start(a);
    }
    if(threadPool->activeThreadCount()>0)
    {
        qDebug() << "active thread: " << threadPool->activeThreadCount();
        threadPool->waitForDone();
    }
}



hookover
hookover
多重继承自QObject?
hookover
hookover
继承QRunnable之后,不能使用信号和槽了……需要和主线程通信,怎么办?
hookover
hookover
非常感谢 你的这份代码,我尝试用一下QThreadPool试试
0
danielgong
danielgong

a.h


#ifndef A_H
#define A_H

#include <QRunnable>
#include <QObject>
class A : public QObject,  public QRunnable
{
    Q_OBJECT
public:
    explicit A(QObject *parent = 0);
    ~A();
    void run();
    
signals:
    void runA();

public slots:
    void slotRunA();
};

#endif // A_H
a.cpp



#include "a.h"
#include<QDebug>
#include <QThread>
A::A(QObject *parent) :
    QObject(parent)
{
    //this->setAutoDelete(true);

}

A::~A()
{
    qDebug() << "~A " << QThread::currentThreadId();
}

void A::run()
{
    qDebug() << "RUN A " << QThread::currentThreadId();
        emit runA();
}

void A::slotRunA()
{
    qDebug() << "slotRunA " << QThread::currentThreadId();
}
b.h



#ifndef B_H
#define B_H

#include <QObject>
#include <QThreadPool>
class B : public QObject
{
    Q_OBJECT
public:
    explicit B(QObject *parent = 0);
    
signals:
    
public slots:
    void catchRunA();

private:
    QThreadPool *threadPool;
};

#endif // B_H

b.cpp

#include "b.h"
#include "a.h"

#include <QDebug>
B::B(QObject *parent) :
    QObject(parent)
{
    threadPool = QThreadPool::globalInstance();
    qDebug() << "active thread: " << threadPool->activeThreadCount();
    qDebug() << "expire time out: " << threadPool->expiryTimeout();
    qDebug() << "max thread count: " << threadPool->maxThreadCount();
    for(int i = 0; i < 10; ++i)
    {
        A *a = new A;
        QObject::connect(a, SIGNAL(runA()), a, SLOT(slotRunA()));
        QObject::connect(a, SIGNAL(destroyed()), this, SLOT(catchRunA()));
        threadPool->start(a);
    }

    if(threadPool->activeThreadCount()>0)
    {
        qDebug() << "actived thread: " << threadPool->activeThreadCount();
        //threadPool->waitForDone();
    }
}

void B::catchRunA()
{
    qDebug() << "B catch run a: " << threadPool->activeThreadCount();
}
main.cpp

#include <QCoreApplication>
#include "b.h"
int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);
    B b;
    return app.exec();
}




0
萨斯辈的呼唤
萨斯辈的呼唤

QThreadPool吧,可以控制多个子线程的活动状态,当你在子线程处理数据时候,如果主线程不知道何时结束,那就waitForDone,然后发送finish信号。

推荐理由,你需要循环创建线程,这对内存开销极大,利用线程池处理是个不错的建议,如果作为全局处理,那就更方便了。具体可以google下哈

hookover
hookover
线程池好像跟CPU有关系,不能创造理想多的线程吧 我现在的思路是创造固定的线程,然后让这些线程一直运行,不停的处理任务
返回顶部
顶部