硬件通信的OO方法......可能是Singleton?

时间:2013-06-26 09:05:59

标签: c++ singleton static-members

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

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

结果,我转向你......过去曾经见过这些问题的SO经验丰富的人。我已经辩论创建一个单身人员来处理所有这些,但我的一些读数让我相信这可能不是可行的方法。在互联网上有一些关于他们的信息,这几乎就像根据我所看到的回答提出一个高度敏感的政治问题。

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

// 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_检查,因此都会打开连接。

结果,我想知道我的选择是什么?我实施单身人士吗?有没有办法让静态变量起作用?或者,我只是评论这个问题,并希望下一个程序员能够理解不打开两个实例来与硬件通信吗?

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

编辑添加:

我刚想到了另一个想法...如果静态bool是静态锁而是怎么办?这样,我可以设置锁定,然后让后续实例尝试获取锁定,如果失败,只需返回一个僵尸类......只是想一想......

3 个答案:

答案 0 :(得分:2)

你是对的,询问单身人士可能会开始一场火焰战,这不会让你更聪明。你最好自己下定决心。如果您了解主要原则,那并不难。

对于你的情况,我会跳过整个分支,因为你的帖子是由FEAR激发的。害怕投机问题。所以,我只是建议你:放松一下。你不能打白痴。一旦你发明了一些傻瓜式的模式,宇宙就会发展并产生一个更好的白痴。不值得努力。将愚蠢的问题留给管理层和人力资源部门,让他们在其他地方工作。

您的任务是提供有关如何使用它的工作解决方案和适当的文档(理想情况下还有测试和示例)。如果你记录使用情况只是创建你的东西​​的一个实例,并执行列出的init和拆解步骤,你可以只是如下所示 - 或者如果不是下一个人的问题。

现实生活中的大多数悲痛不是来自解雇dox,而是因为dox不存在或不准确。所以正好做好这一部分。

一旦完成,当然没有任何事情禁止你在前提条件下给出一些静态或运行时断言:计算你的类实例并声明它不会超过1是不难的。

答案 1 :(得分:0)

如果您有两个硬件实例,该怎么办? [我知道你说它只会是一个 - 但我一直在那里,在“它永远只会是一个!!哦,&lt; swearword&gt;”这方面做到了,现在我们需要使用两个...... “。

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

返回一个僵尸类似乎是一个不好的解决方案 - 抛出一个异常,返回一个错误值,或者某些类似的将是一个更好的选择。

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

对不起,如果这不是真正的“答案”。

答案 2 :(得分:0)

首先,我不认为你可以真正保护这个想象中的未来开发者的任何东西,如果他如此破坏你的代码。评论/ doc应该可以解决问题。如果他错过了,硬件(或代码)可能会崩溃,他会注意到。而且,如果他是重用你的课程的一个很好的理由(比如连接到同类的其他硬件),你不想用令人讨厌的隐藏技巧来阻止他。

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

static std::atomic<bool> running;
...
bool expected = false;
if(running.compare_exchange_strong(expected, true)) {
    ...