在不使用信号和槽机制的情况下,可以通过手写一个回调函数来进行实时数据传递。以下是一个简单的示例:
// MyThread1.h
#include <QThread>
#include <functional>
class MyThread1 : public QThread
{
Q_OBJECT
public:
// 定义回调函数类型
typedef std::function<void(int)> DataReadyCallback;
// 设置回调函数
void setDataReadyCallback(const DataReadyCallback& callback);
protected:
// 线程入口函数
void run() override;
private:
DataReadyCallback m_callback; // 回调函数
};
// MyThread1.cpp
#include "MyThread1.h"
void MyThread1::setDataReadyCallback(const DataReadyCallback& callback)
{
m_callback = callback;
}
void MyThread1::run()
{
// 线程执行的逻辑
while (true)
{
// 生成实时数据
int value = qrand() % 100;
// 调用回调函数,传递数据
if (m_callback)
m_callback(value);
// 休眠一段时间,模拟实时数据产生
msleep(1000);
}
}
// MyThread2.h
#include <QThread>
class MyThread2 : public QThread
{
Q_OBJECT
public:
// 定义回调函数类型
typedef std::function<void(int)> DataCallback;
// 设置回调函数
void setDataCallback(const DataCallback& callback);
protected:
// 线程入口函数
void run() override;
private:
DataCallback m_callback; // 回调函数
};
// MyThread2.cpp
#include "MyThread2.h"
#include <QDebug>
void MyThread2::setDataCallback(const DataCallback& callback)
{
m_callback = callback;
}
void MyThread2::run()
{
// 线程执行的逻辑
// 这里可以不做任何操作,因为数据通过回调函数进行处理
}
在以上示例中,MyThread1 和 MyThread2 分别是继承自 QThread 的线程类,其中 MyThread1 负责生成实时数据并通过回调函数 m_callback 进行传递,而 MyThread2 负责接收数据并通过回调函数 m_callback 进行处理。
在使用时,可以在主线程中实例化并启动这两个线程,并设置回调函数:
// 在主线程中创建两个线程对象
MyThread1 *thread1 = new MyThread1();
MyThread2 *thread2 = new MyThread2();
// 设置回调函数
thread1->setDataReadyCallback([&](int value) {
// 在回调函数中处理接收到的数据
qDebug() << "Received data:" << value;
});
// 启动两个线程
thread1->start();
thread2->start();
这样,当 MyThread1 生成实时数据时,会调用设置的回调函数,并传递数据,从而实现了通过手写回调函数的方式进行实时数据传递。需要注意的是,在使用回调函数时,需要注意线程安全性和资源。
上述示例中的回调函数在多线程环境中可能存在线程安全和资源安全的问题。因为在 MyThread1 线程中的回调函数 m_callback 可能会被多个线程同时调用,从而导致竞态条件(Race Condition)和资源冲突(Resource Conflict)等问题。
为了解决这些问题,可以采取以下措施:
使用互斥锁(Mutex)或其他线程同步机制来保护回调函数的访问,确保每次只有一个线程能够访问回调函数。
在回调函数中避免访问共享资源,或者对共享资源进行加锁保护,以防止多线程访问导致的资源冲突。
在回调函数中避免执行耗时的操作,以减小对线程执行的影响。
考虑使用线程安全的数据结构,如线程安全队列(Thread-safe Queue)等,来确保数据传递过程中的线程安全性。
下面是一个简单的示例,展示了如何使用互斥锁来保护回调函数的访问:
// MyThread1.h
#include <QThread>
#include <functional>
#include <QMutex>
class MyThread1 : public QThread
{
Q_OBJECT
public:
// 定义回调函数类型
typedef std::function<void(int)> DataReadyCallback;
// 设置回调函数
void setDataReadyCallback(const DataReadyCallback& callback);
protected:
// 线程入口函数
void run() override;
private:
DataReadyCallback m_callback; // 回调函数
QMutex m_mutex; // 互斥锁,用于保护回调函数的访问
};
// MyThread1.cpp
#include "MyThread1.h"
void MyThread1::setDataReadyCallback(const DataReadyCallback& callback)
{
QMutexLocker locker(&m_mutex); // 加锁
m_callback = callback;
}
void MyThread1::run()
{
// 线程执行的逻辑
while (true)
{
// 生成实时数据
int value = qrand() % 100;
// 调用回调函数,传递数据
QMutexLocker locker(&m_mutex); // 加锁
if (m_callback)
m_callback(value);
locker.unlock(); // 解锁
// 休眠一段时间,模拟实时数据产生
msleep(1000);
}
}
在以上示例中,通过使用 QMutex 互斥锁来保护回调函数的访问,确保每次只有一个线程能够访问回调函数,从而避免了竞态条件和资源冲突的问题。但需要注意,使用互斥锁可能会引入性能开销和潜在的死锁问题,因此在设计多线程程序时需要慎重考虑线程安全