gpt4 book ai didi

c++ - 在线程之间安全地分发指针更新

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:16:47 25 4
gpt4 key购买 nike

长话短说:

 class Controller
{
public:
volatile Netconsole* nc;
void init(); //initialize the threads
void calculate(); // handler for the "mothership app"
void senderThreadLoop(); //also calls reinitNet() if connection is broken.
void listenerThreadLoop();
inline void reinitNet(){ delete nc; nc = new Netconsole(); }
}

//里面 Json::Value header = nc->Recv();

错误:将“volatile Netconsole”作为“this”参数传递会丢弃限定符 [-fpermissive]

如果实用程序类被重新实例化,则指向两个线程之间共享的实用程序类 (Netconsole) 实例的指针必须在两个线程内更新,但将其声明为 volatile 会产生上述错误。如果它只在一个线程内更新,另一个线程可能仍然使用旧的、无效的指针。如何确保它在两者中都已更新但通过指针使用方法不会触发上述错误?

扩展信息:

我正在编写的“智能胶合逻辑”库用于在第 3 方软件和自定义设备之间传递和转换消息。它由三个基本线程组成:

  • 处理程序:第 3 方应用程序的主线程定期调用我的库中的“计算”函数来处理新的更新——要发送的数据、接收到的数据
  • 一个发送线程,它转换并发送处理程序插入发送缓冲区的任何内容
  • 一个监听器线程,用于转换从设备接收到的任何数据并将其推送到接收缓冲区。

发送者和监听者线程都使用相同的实用程序类来处理与设备的网络通信;初始化后,该类创建到设备的连接,两个线程分别执行阻塞读取或等待新数据发送。如果出现任何问题,发送方线程将执行所有“维护”工作,而监听方线程将进入安全状态,等待连接恢复。

现在,由于这两个线程共享一个到设备的连接,它们都共享通信类的同一个实例,作为指向该类的指针。

问题出在重新连接的过程中——它涉及利用析构函数和构造函数中已经存在的安全关闭和初始化来销毁和创建辅助类实例。结果指针改变了。如果没有 volatile,监听器很可能不会收到更新后的指针。对于 volatile,它会抗议 - 不必要的,因为 nc (指针)不会在随机时刻改变 - 首先会通知监听器有问题,然后它会进入安全状态,但不会对“nc”执行任何操作并通知发送者它已准备就绪。只有这样,发送方才执行修复并通知收听方恢复正常操作。

那么在这种情况下正确的解决方案是什么?

最佳答案

您需要的是一系列操作。生产线程有 2 个相关操作:“初始化新的 Netconsole”和“写入指针”。消费线程还有两个操作:“读指针”和“使用新的Netconsole对象”。这 4 个操作必须按完全的顺序排列,以便更新可见。

到目前为止,实现这一目标的最简单方法是两个内存屏障。写入屏障(指针写入上的 std::memory_order_release)防止前两个操作被重新排序,读取屏障(指针加载上的std::memory_order_acquire)防止最后两个操作被重新排序。

由于这两个线程独立运行,您的程序正确性不应取决于特定对象更新是否发生在特定对象使用之前。更新线程可能只是有点慢,这不应该破坏您的程序。因此,写入和读取之间的第三次排序并不真正相关,您不应该尝试“修复”它。

总结一下:是的,这 4 个操作必须以完全正确的顺序发生才能使结果可见,但是如果第二个和第三个操作是重新排序,然后更新对消费线程完全不可见。这是一个原子更新,全有或全无。

还有清理旧对象的问题。生产线程不能假设消费线程已经看到指针更新。必须有同步以确保两个线程都同意旧对象未被使用。最简单的是如果生产线程在创建新对象后严格不使用旧对象(内存屏障在这里有帮助),并且消费线程一知道有新对象就清理旧对象(因为那严格发生在读取屏障之后,因此发生在写入屏障之后,进而发生在生产线程最后一次使用之后)

关于c++ - 在线程之间安全地分发指针更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32567607/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com