• 6529阅读
  • 11回复

[讨论]Qt多线程传输变量的问题 [复制链接]

上一主题 下一主题
离线liruigood
 

只看楼主 倒序阅读 楼主  发表于: 2016-12-06
问题如下:
   我子类化Qthread创建了三个线程类,Qtcpthread用来通讯;Qserialthread用来读取传感器串口的值;Qcontrolthread用来做pid等算法控制;前两者读取到的反馈值传给第三者,第三者做处理后将输出值传给Qtcpthread,用于直接控制;这三个线程run()都是while死循环;数据传输是用信号与槽的方式,emit和slot,他们分别在主线程,也就是ui线程中转;问题出在Qcontrolthread emit一个信号给Qtcpthread,程序运行出现了中断,出现了如下错误HEAP[demo.exe]: HEAP: Free Heap block 7d2ecd8 modified at 7d2ee20 after it was freed。然后我把Qcontrolthread线程中的emit信号发送屏蔽掉不发送,同时运行就没有问题。只运行Qtcpthread和Qserialthread和只运行Qserialthread和Qcontrolthread信号传输也都没有问题。所以就不知道是哪个模块出来问题,求解?
这是Controlthread的run()函数:

void ControlThread::run()
{
    static int count = 0;
    while (true)
    {
        count++;
        if (count>50000)
        {
            AutoControlPacket.clear();
            //float OutputPosition = Torque_Control_PID(ControlData.MorotData.CurrentPoition,60*182.045);
            AutoControlPacket.name = "AotoControl";
            AutoControlPacket.hexString.append(QString("VL.CMDU %1\r\n").arg(500));    
            emit SendControlCmdPacket(AutoControlPacket);
            count = 0;
        }
    }
}
emit SendControlCmdPacket(AutoControlPacket);这句屏蔽掉就没事;
AutoControlPacket是自定义的一个类,Q_DECLARE_METATYPE一下,再注册一下就可以传输了。
我在Qtcpthread检测Controlthread传过来的数据是不是空,如果不为空,就会把数据发送出去;

    //clientConnection->waitForReadyRead(200);
                //单包发送模式 Ui按钮控制命令
                if (!sendLoopPacketPersistent.hexString.isEmpty())
                {  
                    Sendpacket.name = sendLoopPacketPersistent.name;
                    Sendpacket.hexString = sendLoopPacketPersistent.hexString;
                    clientConnection->write(Sendpacket.getByteArray());
                    clientConnection->waitForBytesWritten(10);
                    sendLoopPacketPersistent.clear();
                    Sendpacket.clear();    
                }
                //continue;
                //发送自动控制命令包
                if (!sendControlPacket.hexString.isEmpty())
                {
                    Sendpacket.name = sendControlPacket.name;
                    Sendpacket.hexString = sendControlPacket.hexString;
                    clientConnection->write(Sendpacket.getByteArray());
                    clientConnection->waitForBytesWritten(10);
                    Sendpacket.clear();
                    sendControlPacket.clear();
                }
                //循环中察看连接状态
                if (clientConnection->state() != QAbstractSocket::ConnectedState)            
                {
                    emit connectstatus("Connection broken");
                    break;
                }
                //数据读取模式
                QByteArray readdata;
                readdata.clear();
                readdata = clientConnection->readAll();
                clientConnection->waitForReadyRead(10);
                if (!readdata.isEmpty())
                {
                    emit passdataout(readdata);
                }            
            }





离线patrickwf

只看该作者 1楼 发表于: 2016-12-07
贴代码比较直观
离线bran_lee

只看该作者 2楼 发表于: 2016-12-07
AutoControlPacket到底是什么时候创建的?是全局的还是局部的?信号传的是引用?传到另一个线程后AutoControlPacket会不会被析构?
当你只有锤子时,你看什么都像是钉子!
离线liruigood

只看该作者 3楼 发表于: 2016-12-07
回 bran_lee 的帖子
bran_lee:AutoControlPacket到底是什么时候创建的?是全局的还是局部的?信号传的是引用?传到另一个线程后AutoControlPacket会不会被析构? (2016-12-07 11:51) 

AutoControlPacket是ControlThread的私有变量,槽函数是这样
void demo::semdControlPacket(Packet packet)
{
    Packet resu = packet;
    emit sendcontroloutput(resu);
}
导一下emit sendcontroloutput(resu)再把数据传到Qtcpthread线程;用于控制;

奇怪的是今天我把上面代码这步分删了
          //发送自动控制命令包
                if (!sendControlPacket.hexString.isEmpty())
                {
                    Sendpacket.name = sendControlPacket.name;
                    Sendpacket.hexString = sendControlPacket.hexString;
                    clientConnection->write(Sendpacket.getByteArray());
                    clientConnection->waitForBytesWritten(10);
                    Sendpacket.clear();
                    sendControlPacket.clear();
                }
在Qtcpthread中变成了这样:
     //单包发送模式 Ui按钮控制命令
                if (!sendLoopPacketPersistent.hexString.isEmpty())
                {  
                    Sendpacket.name = sendLoopPacketPersistent.name;
                    Sendpacket.hexString = sendLoopPacketPersistent.hexString;
                    clientConnection->write(Sendpacket.getByteArray());
                    clientConnection->waitForBytesWritten(10);
                    sendLoopPacketPersistent.clear();
                    Sendpacket.clear();    
                }
                //continue;
              
                //数据读取模式
                QByteArray readdata;
                readdata.clear();
                readdata = clientConnection->readAll();
                clientConnection->waitForReadyRead(10);
                if (!readdata.isEmpty())
                {
                    emit passdataout(readdata);
                }            
            }
一次写入,一次读取;写入的时候把ControlThread传的数据append了一下,与其他数据一起发送,而不是开始那样在while里检测是否有数据,二次写入;
开始是过两分钟后程序自动断点崩溃,现在不知为什么却没发现断的情况。这种情况肯定是野指针的问题,可关键是不知道在哪,程序像一个定时炸弹;
离线sunnyw0n

只看该作者 4楼 发表于: 2016-12-07
void demo::semdControlPacket(Packet packet)
{
    Packet resu = packet;
    emit sendcontroloutput(resu);
}
Packet 出了函数作用域不是析构了么?
离线liruigood

只看该作者 5楼 发表于: 2016-12-07
回 sunnyw0n 的帖子
sunnyw0n:void demo::semdControlPacket(Packet packet)
{
    Packet resu = packet;
    emit sendcontroloutput(resu);
}
....... (2016-12-07 17:05) 

你的意思是AutoControlPacket这个ControlThread的私有变量被传完之后构析了?我之前一直以为emit 的参数是不会出enit所在的函数的作用域的。谢谢啊,我再看看。
离线patrickwf

只看该作者 6楼 发表于: 2016-12-08
回 liruigood 的帖子
liruigood:你的意思是AutoControlPacket这个ControlThread的私有变量被传完之后构析了?我之前一直以为emit 的参数是不会出enit所在的函数的作用域的。谢谢啊,我再看看。 (2016-12-07 18:50) 

要看是不是在同一个线程的,一般同一个线程是立即执行信号关联的槽函数,不同线程就要把槽函数的加到对应线程的事件循环中了。
离线curiosity

只看该作者 7楼 发表于: 2017-01-14
LZ您好,我最近也在做一个多线程编程的题目,主要内容是我有一个串口接收线程,一个读取相机图像的线程,还有一个用来处理这两个线程传过来的数据的线程,叫做处理线程。
我想问一下到底应该怎么协调好这三个线程的同步关系,因为我在处理线程中要进行循环处理,并且是要在完整接收到相机图像和串口数据之后再进行处理,
如果用信号槽给这个处理线程发信号的话,需要考虑同步的问题,因为我这个处理线程可能比较慢,如果处理线程在没处理完之前串口线程和相机线程又发过来信号的话,这个信号是会阻塞的吗?但其实我不想阻塞,因为的处理线程的目的是想时刻处理最新的数据,即最好处理线程运行完直接又取一个最新的串口线程和相机线程的数据继续处理,这个应该怎么弄呢?

我觉得您的项目跟我的好像还比较像,所以想问一下您,多谢!
管它真理无穷,进一寸有一寸的欢喜!
离线liruigood

只看该作者 8楼 发表于: 2017-02-12
回 curiosity 的帖子
curiosity:LZ您好,我最近也在做一个多线程编程的题目,主要内容是我有一个串口接收线程,一个读取相机图像的线程,还有一个用来处理这两个线程传过来的数据的线程,叫做处理线程。
我想问一下到底应该怎么协调好这三个线程的同步关系,因为我在处理线程中要进行循环处理,并且是要在完整接 .. (2017-01-14 23:05) 

抱歉,假期回家很长时间没上论坛了,也没注意到消息。你现在做的怎么样了?你说的很对,除了用信号与槽的机制,你还可以用全局变量在线程之间传值,但是得注意线程安全。

只看该作者 9楼 发表于: 2017-02-14
楼主啊,你这个多数据处理线程是嵌入式的吗,为什么我的仅开启一个线程,就会黑屏啊(找的一个示例代码。开启arm板第一次点击开启子线程,屏幕黑屏,但是qdebug能正常打印东西,即程序是没死的,就是黑屏了) 能不能指点一二

只看该作者 10楼 发表于: 2017-02-14
楼主啊,你这个多数据处理线程是嵌入式的吗,为什么我的仅开启一个线程,就会黑屏啊(找的一个示例代码。开启arm板第一次点击开启子线程,屏幕黑屏,但是qdebug能正常打印东西,即程序是没死的,就是黑屏了) 能不能指点一二
离线liruigood

只看该作者 11楼 发表于: 2017-02-20
回 哥依然潇洒 的帖子
哥依然潇洒:楼主啊,你这个多数据处理线程是嵌入式的吗,为什么我的仅开启一个线程,就会黑屏啊(找的一个示例代码。开启arm板第一次点击开启子线程,屏幕黑屏,但是qdebug能正常打印东西,即程序是没死的,就是黑屏了)[表情] 能不能指点一二 (2017-02-14 14:32) 

我的是pc跑的,arn跑系统我没有用过。会不会你的arm内存不够,影响了图形显示?考虑下资源占用。
快速回复
限100 字节
 
上一个 下一个