【问题标题】:QT 4.3 passing class pointer between threadsQT 4.3 在线程之间传递类指针
【发布时间】:2015-12-13 15:07:58
【问题描述】:

我正在使用 QT 4.3.1(遗留代码必须使用它)并且我正在使用信号和插槽在我的工作线程和 GUI 线程之间传递一个类引用。

如果此类由本机类型(Qstring、int、unsigned char)组成,QT 是否会对此类执行原子操作,还是我仍然需要 QMutex?在线程之间传递类或数据缓冲区的引用是否安全,或者是否有更好的方法来共享它并防止并发访问?

我有一个类,COMinfo 由另一个类和一个使用本机类型的结构组成:

typedef struct Port_Check_Struct
{

    U_BYTE  command       :4;
    U_BYTE  spare15_4   :2; /* spare bits */
    U_BYTE  status       :2; 

} PORT_CHECK_STRUCT;


class PortInfo
{
public:

    PortInfo();

    QString     portName;
    U_BYTE      Dir;
    UNSIGNED16  Addr;
    U_BYTE      Size;

    bool        active;
    U_BYTE      lastused;
    U_BYTE      currused;
    U_BYTE      errorCntr;

    U_BYTE      portBuff[100];
    U_BYTE      dataBuff[100];

    PORT_CHECK_STRUCT   *portCheck;
};


class COMInfo
{
public:
    UNSIGNED8   errorStatus;

    UNSIGNED16  COMaddr;

    PortInfo    portInfo[4];
};

    // Define Meta Types for SIGNAL/SLOT CROSS THREAD TYPES
    qRegisterMetaType<COMInfo>("COMInfo");

我使用 qRegisterMetaType() 将数据类型注册到 MOC。

我在我的工作线程和 GUI 线程之间传递引用,如下所示:

emit COM_DATA_UPDATE(COM_Info.portInfo[0].dataBuff)

QT 与此参考有何关系?是浅拷贝吗?需要复制构造函数吗?

信号定义为:

void   COM_DATA_UPDATE(const U_BYTE* msg);

还有一个信号我通过了实际的 const 类引用:

void   INFO_UPDATE(const COMInfo& comInfo);

【问题讨论】:

  • 原子性是不可组合的。连接在结构中的两个原子访问值不是共同原子的。原子性通常不能提供足够的线程安全行为。线程安全是你正在做的事情的一个功能,因此你需要什么保证。拥有线程安全的简单方法是从不共享数据,只共享副本。其他所有内容往往过于简化、错误、非常复杂,或者通常两者兼而有之。

标签: c++ multithreading qt


【解决方案1】:

“如果这个类由本机类型组成,QT 是否对它执行原子操作” - 语言是 C++,Qt 只是一个库。因此,当从多个线程访问变量并且通常的 C++ 多线程规则及其内存模型(自 C++11 起)适用时,Qt 不会发挥任何作用。然而,信号/槽机制实现了消息传递机制用于线程间通信:Queued connections(另请参阅thread synchronisation 上的页面)通过复制参数将参数从一个线程传递到另一个线程。即,传递诸如 QString、int、double 之类的值类型是安全的——接收线程将对发送线程数据的副本进行操作,并且没有需要锁定的并发访问。由 const 引用传递的信号/槽参数也将被信号/槽系统复制。

但是,如果您将指针作为参数传递或包含在结构中,指针将被复制,而不是它指向的对象(如果没有自定义复制 ctor/赋值运算符实现)否则)。因此,访问传递的指针安全,您需要一个同步机制,例如互斥锁。

在您的示例中,PORT_CHECK_STRUCT *portCheckvoid COM_DATA_UPDATE(const U_BYTE* msg) 都有这个问题(在传递 PortInfo 对象时)。我建议通过 std::array (或 std::vector/QVector 如果你不能使用 C++11)传递数据。

【讨论】:

  • QT 是否仍会在类构造中复制这些数据类型,或者我的类是否应该从 QObject 派生?另外,不使用 C++11 的编译器是 C++98
  • 不,永远不要将 QObject 用于值类(它的复制 ctor 和赋值运算符是私有的,这是有原因的)。只需声明元类型。
  • 只是关于我的旧代码的一个问题,如果我没有复制构造函数,这些指针如何工作? QT 是否使用默认构造函数深拷贝指针?
  • 不,没有深度复制,只会复制指针,而不是对象。这是 C++ 中结构/类的默认复制行为,与 Qt 无关。这就是为什么我指出你的例子中的指针(原文如此)是有问题的。
  • 谢谢!检查我是否理解这一点。因此,指针被复制,并且由于线程共享内存空间,它们在理论上仍将指向有效对象,但如果对象超出范围,则可能具有潜在的破坏性。如果没有实现互斥锁或其他方法,两个线程也可以同时访问指针指向的内容。
猜你喜欢
  • 1970-01-01
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多