2

我正在做一个项目,我需要通过 UDP 与特定的盒子交谈。在任何给定时间,只有一个盒子连接到系统。连接应该持续整个程序的持续时间。

我写了一个类(耶!)为硬件提供必要的数据。然而,我的主要问题是,现在我必须考虑这样一个事实,即某人(未来的程序员很可能会忽略我所有非常简洁的评论;))可能会创建多个此类的实例。这很可能会导致一些有趣且相当有趣的崩溃,其中有问题的硬件想知道为什么它要从同一台机器上的两个套接字接收数据。更麻烦的是创建对象实际上会产生一个定期发送更新的线程。所以你可以想象,如果我想象中的未来程序员做一些事情,比如创建这些对象的链表(毕竟这是 C++,我们有能力做这些事情),一段时间后 CPU 可能不会很高兴。

因此,我求助于您……过去曾见过此类问题的 SO 中更有经验的人。我一直在讨论创建一个单例来处理所有这些,但我的一些阅读让我相信这可能不是要走的路。互联网上有大量关于他们的信息,这几乎就像根据我看到的回复提出一个高度敏感的政治问题。

我开发的一种可以保留尽可能多代码的替代方法是仅使用静态布尔值来跟踪是否有活动线程将数据传递给硬件。但是,我怀疑我的方法可能会在我有竞争线程尝试同时访问该类的情况下导致竞争条件。到目前为止,这是我所拥有的:

// in MyClass.cpp:
static bool running_ = false;  // declared in the class in the .h, but defined here
MyClass::MyClass() {
  // various initialization stuff you don't care about goes here
  if (pthread_create(mythread_, NULL, MyThreadFunc, this) != 0) {
    // error
  }
  else {
    // no error
  }
}

static void* MyClass::MyThreadFunc(void* args) {
  MyClass myclass = static_cast<MyClass>(args);
  // now I have access to all the stuff in MyClass
  // do various checks here to make sure I can talk to the box
  if (!running_) {
    running_ = true;
    // open a connection
    while (!terminate) {  // terminate is a flag set to true in the destructor
      // update the hardware via UDP
    }
    // close the socket
    running_ = false;
  }
}

虽然我当然注意到这将仅检查一个处于活动状态的实例,但仍有可能两个并发线程将同时访问 !running_ 检查并因此打开连接。

结果,我想知道我的选择是什么?我要实现单例吗?有没有办法让静态变量工作?或者,我是否只是评论这个问题并希望下一个程序员明白不要打开两个实例来与硬件对话?

一如既往,感谢您的帮助!

编辑添加:

我刚想到另一个想法……如果静态布尔值是静态锁呢?这样,我可以设置锁,然后让后续实例尝试获取锁,如果它们失败,则返回一个僵尸类......只是一个想法......

4

3 回答 3

2

你是对的,询问单身很可能会引发一场激烈的战争,这不会让你变得更聪明。你最好自己拿主意。如果您了解主要原则,这并不难。

对于你的情况,我会跳过整个分支,因为你的帖子是出于恐惧。对投机问题的恐惧。所以让我建议你:放松。你不能和白痴打。一旦你发明了一些万无一失的模式,宇宙就会进化,并会产生一个更好的白痴来绕过它。不值得努力。把白痴问题留给管理层和人力资源部,让他们在其他地方就业。

您的任务是提供可行的解决方案和有关如何使用它的适当文档(最好也包含测试和示例)。如果您记录使用来创建您的东西的单个实例,并执行列出的初始化和拆卸步骤,您可以按照以下说明进行操作 - 或者如果不是,那就是下一个人的问题。

大多数现实生活中的悲伤不是来自解雇 dox,而是那个 dox 不存在或不准确。所以只要正确地做那部分。

一旦完成,当然没有什么可以禁止您在前提条件下使用一些静态或运行时断言:计算您的类的实例并断言它不会超过 1 并不难。

于 2013-06-26T09:43:00.620 回答
0

首先,如果这位想象中的未来开发人员如此热衷于破坏您的代码,我认为您无法真正保护任何东西。评论/文档应该可以解决问题。如果他错过了它们,硬件(或代码)可能会崩溃,他会注意到。此外,如果他作为重用你的类的一个很好的理由(比如连接到一些其他同类硬件),你不想用讨厌的隐藏技巧来阻止他。

这就是说,对于您的示例,我会考虑使用 anatomic<bool>来避免任何并发问题,并使用 compare_exchange 成员函数而不是if(!running) running = true

static std::atomic<bool> running;
...
bool expected = false;
if(running.compare_exchange_strong(expected, true)) {
    ...
于 2013-06-26T09:39:33.207 回答
0

如果您有两个硬件本身的实例怎么办?[我知道你说它只会是一个——但我去过那里,在“永远只会是一个!哦,<swearword>,现在我们需要使用两个......”这方面做到了。 ]。

当然,你if(running_)是一个竞争条件。你真的应该使用某种原子类型,这样你就不会一次尝试两次启动课程。这也不会阻止某人尝试启动整个程序的两个实例。

返回僵尸类似乎是一个糟糕的解决方案——抛出异常、返回错误值或类似的方法会是更好的选择。

是否可以让“另一方”控制连接数?换句话说,如果第二个实例尝试通信,它会从收到消息“抱歉,已经有连接”的硬件返回错误?

抱歉,如果这不是真正的“答案”。

于 2013-06-26T09:27:48.473 回答