qt中其他线程的信号向异步线程的槽传指针与释放指针问题

发现qt中信号槽传指针的方式进行时,会发生释放不掉指针所分配的空间的情况。

定义一个信号

void emit_showTime(Data*);


void slot_showTime(Data*);

在发出信号之前动态创建一个Data的指针对象,并分配空间。传入信号中。然后在槽中进行delete 释放所分配的空间。


发现所传如的指针是正确的(地址都相同),但确不能如愿的释放掉该指针所分配的空间。使得程序占用内存不断增加。


有兴趣的可以试试,放在一个QTimer中不断执行。就能看出内存不断增加。

当信号与槽采用传值或引用时,却又是正确的。

定义一个信号

void emit_showTime(Data);


void slot_showTime(Data);

以此方式,则不会出现内存一直增加的问题。

不是一个好的做法。原因在于发送信号的地方很有可能是在对象的作用域范围,当信号发出后,槽函数立即被调用,而调用还没有返回的情况下,你却强行删除了对象,这样就存在一个潜在的致命错误。举个例子
void func{
Data data;
emit emit_showTime(&data); //这行意味着槽函数被马上调用并等待返回,如果在槽函数中删除data就会存在一个内存操作的危险
}
这类似于下面的操作
func{
Data data;
delete &data;
}
尽管你是使用动态创建对象,这也不是一个好的编程习惯,最好是这样
func{
Data *data = new Data;
emit emit_showTime(data);
delete data;
}

Qt的signal/slot机制原理

signal/slot在底层会使用三种方式传递消息。参见QObject::connect()方法:
bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoCompatConnection )
最后一个参数是就是传递消息的方式了,有四个取值:

Qt::DirectConnection
When emitted, the signal is immediately delivered to the slot.
假设当前有4个slot连接到QPushButton::clicked(bool),当按钮被按下时,QT就把这4个slot按连接的时间顺序调用一遍。显然这种方式不能跨线程(传递消息)。

Qt::QueuedConnection
When emitted, the signal is queued until the event loop is able to deliver it to the slot.
假设当前有4个slot连接到QPushButton::clicked(bool),当按钮被按下时,QT就把这个signal包装成一个 QEvent,放到消息队列里。QApplication::exec()或者线程的QThread::exec()会从消息队列里取消息,然后调用 signal关联的几个slot。这种方式既可以在线程内传递消息,也可以跨线程传递消息。

Qt::BlockingQueuedConnection
Same as QueuedConnection, except that the current thread blocks until the slot has been delivered. This connection type should only be used for receivers in a different thread. Note that misuse of this type can lead to dead locks in your application.
与Qt::QueuedConnection类似,但是会阻塞等到关联的slot都被执行。这里出现了阻塞这个词,说明它是专门用来多线程间传递消息的。

Qt::AutoConnection
If the signal is emitted from the thread in which the receiving object lives, the slot is invoked directly, as with Qt::DirectConnection; otherwise the signal is queued, as with Qt::QueuedConnection.
这种连接类型根据signal和slot是否在同一个线程里自动选择Qt::DirectConnection或Qt::QueuedConnection

这样看来,第一种类型的效率肯定比第二种高,毕竟第二种方式需要将消息存储到队列,而且可能会涉及到大对象的复制(考虑sig_produced(BigObject bo),bo需要复制到队列里)。
 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt ,如果你需要在不同线程传递指针,可以使用 `QMetaObject::invokeMethod()` 方法来实现。这个方法可以在一个对象的线程异步调用一个函数,同时将指定的参数传递给它。 具体来说,你需要在信号连接时指定连接类型为 `Qt::QueuedConnection`,这样就可以确保函数在接收到信号时在目标线程执行。然后,在函数使用 `QMetaObject::invokeMethod()` 方法异步地调用目标函数,将指针参数传递给它。 下面是一个示例代码: ```c++ // 定义一个自定义信号,其参数为指针类型 class MyObject : public QObject { Q_OBJECT signals: void mySignal(MyObject* obj); }; // 定义一个函数,其参数为指针类型 void MyObject::mySlot(MyObject* obj) { // 在函数使用 QMetaObject::invokeMethod() 方法异步地调用目标函数 QMetaObject::invokeMethod(this, "myTargetFunction", Qt::QueuedConnection, Q_ARG(MyObject*, obj)); } // 定义一个目标函数,其参数为指针类型 void MyObject::myTargetFunction(MyObject* obj) { // 处理接收到的指针参数 // ... } ``` 在这个示例,当信号 `mySignal` 被发射时,函数 `mySlot` 将被调用,并在其使用 `QMetaObject::invokeMethod()` 方法异步地调用目标函数 `myTargetFunction`,将指针参数传递给它。注意,这里指针类型的参数需要使用 `Q_ARG()` 宏进行包装,以便正确地传递给 `QMetaObject::invokeMethod()` 方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值