在C ++中删除和重构单例

时间:2009-12-07 04:42:17

标签: c++ linux qt

我有一个应用程序,它运行在与不同传感器连接的控制硬件上。在加载应用程序时,它会逐个检查各个传感器,以确定是否根据预定义的协议与传感器进行了正确的通信。

现在,我已经实现了将单个传感器通信检查为单例线程的代码,以下是运行函数,它使用select系统调用和管道进行进程间通信,以指示线程结束。

void SensorClass::run()
{
    mFdWind=mPort->GetFileDescriptor();
    fd_set readfs;
    int max_fd = (mFdWind > gPipeFdWind[0] ? mFdWind : gPipeFdWind[0]) + 1;
    int res;

    mFrameCorrect=false;
    qDebug("BEFORE WHILE"); 
    while(true)
    {
        qDebug("\n IN WHILE LOOP"); 
        usleep(50);
        FD_ZERO(&readfs);
        FD_SET(mFdWind,&readfs);
        FD_SET(gPipeFdWind[0],&readfs);

        res=select(max_fd,&readfs,NULL,NULL,NULL);
        if(res < 0)
            perror("Select Failed");
        else if(res == 0)
            puts("TIMEOUT");
        else
        {
            if(FD_ISSET(mFdWind,&readfs))
            {
                puts("*************** RECEIVED DATA ****************");
                mFrameCorrect=false;
                FlushBuf();
                //int n=mPort->ReadPort(mBuf,100);
                int n=mPort->ReadPort(mBuf,100);

                if(n>0)
                {
                    Count++;


                    QString str((const char*)mBuf);
                    //qDebug("\n %s",qPrintable(str));
                    //See if the Header of the frame is valid
                    if(IsHeaderValid(str))
                    {
                        if( (!IsCommaCountOk(str)) || (!IsChecksumOk(str,mBuf)) ||  (!CalculateCommaIndexes(str))  ) 
                        {

                            qDebug("\n  not ok");
                            mFrameCorrect=false;
                        } //if frame is incorrect
                        else 
                        {
                            qDebug("\n  OK");
                            mFrameCorrect=true;
                        }//if frame is correct(checksum etc are ok)
                    }//else if header is ok
                }//if n > 0
            }//if data received FD_ISSET
            if(FD_ISSET(gPipeFdWind[0],&readfs))
                break;
        }//end nested else res not <= 0
    }//infinite loop  
}

以上线程从主GUI线程开始运行。这很好。问题是我给了用户一个随意重新测试子系统的选项。为此,我使用

删除单例实例
delete SensorClass::instance();

然后使用

重启单例
SensorClass::instace()->start();

问题是这次控制是在run()函数的while循环中出现的,当进入while循环时,我的猜测是管道读取再次从写入管道读取到最后一次。我曾尝试使用fflush()来清除I / O但没有运气。 我的问题是

  1. 我是否正在考虑正确的方向?

  2. 如果是,那么我们如何清除管道?

  3. 如果没有人可以提出为什么选择性重新测试不起作用?

  4. 提前致谢..

4 个答案:

答案 0 :(得分:1)

fflush清除输出缓冲区。如果要清除输入缓冲区,则需要读取数据或搜索到最后。

我不相信“单身人士”模式是合适的。还有其他方法可以确保每个硬件最多只有一个实例。如果您以后想要多个线程,每个线程使用不同的传感器怎么办?

答案 1 :(得分:1)

让我们假设你是通过继承QThread(你没有指定)来创建这个线程的。来自QThread::~QThread ()的文档:

  • 请注意,删除QThread对象不会停止执行它所代表的线程。删除正在运行的QThread(即isFinished()返回false)可能会导致程序崩溃。

因此声明delete SensorClass::instance();可能是一个非常非常糟糕的主意。特别是,考虑到这个缺陷,对这个程序的行为有任何意义。在继续之前,您可能希望找到一种方法来删除实例并确保线程也消失。

另一个问题浮现在脑海中。当你运行delete SensorClass::instance()时,你会摆脱一些对象(在堆上,人们希望)。谁告诉单身人士持有人它的对象已经消失了?例如。以便下一次调用SensorClass::instance()知道它需要分配另一个实例?这是否在SensorClass::~SensorClass中正确处理?

假设这不是问题。这可能意味着指向实例的指针保存在全局变量(或者,例如类级静态成员)中。它可能对这种情况无关紧要,但访问该成员是否正确同步?即有没有一个互斥锁被锁定每次访问它?

答案 2 :(得分:1)

你真的不想在线程中运行初始化。这是第一个让你的问题大大复杂化的问题,而且出于某种原因没有人指出这种问题。

只需将初始化作为自己的函数,然后有一个保护变量并锁定,并在启动时将所有使用它的东西分别初始化。

答案 3 :(得分:0)

所以你通过向管道写东西来发信号,管道只创建一次 - 即在后来的线程中重用?

远离管道读取信号。假设你通过写一个字节来发信号,那么你可以做类似的事情(NB,没有错误检查等):

if(FD_ISSET(gPipeFdWind[0],&readfs)) {  
    char c;  
    read(gPipeFdWind[0], &c, 1);  
    break;  
}

还有 用于处理套接字I / O的Qt类,例如: QTcpSocket,这将使代码不仅更清洁,也更加跨平台。或者至少QSocketNotifier来抽象选择。