• 7560阅读
  • 10回复

一个多线程的问题 [复制链接]

上一主题 下一主题
离线kenangogogo
 

只看楼主 倒序阅读 楼主  发表于: 2008-09-05
— 本帖被 XChinux 从 General Qt Programming 移动到本区(2011-01-02) —
各位高手大哥:
    小弟新学Qt,最近弄了一个多线程的程序,一个线程用于计算,一个线程就是GUI主线程,现在我想在主线程中知道有关计算的进度情况,所以我在主线程中设计了一个进度条,同时在计算线程中用一个信号来通知主线程,完成进度条的显示情况。想法是这样,但实际做起来,发现设计的SIGNAL并没有被SLOT响应,小第对多线程的知识知道的不多,希望高手能够指点一下,小弟感激不尽。
离线water_wf

只看该作者 1楼 发表于: 2008-09-05
贴代码
离线kenangogogo

只看该作者 2楼 发表于: 2008-09-05
好的,谢谢。
先看这个显示出错消息的例子吧。
void  CompThread::run()
{
    //mutex.lock();
    if(m_SourceFilePath.isEmpty() || m_ReviseFileDir.isEmpty())
    {
        emit postErrorMessage("didn't select the source file path or the revise files dir .");
        //dispatchTime.wait(&mutex);
        //mutex.unlock();
}
..........
}
上面的postErrorMessage(const QString&)是我自己定义的一个信号。在主线程中,设计了一个slot去响应它。slot代码如下:
void SegyRevise::showErrorMessage(const QString& errorMessage)
{
    QErrorMessage error;
    error.showMessage(errorMessage);
    //qDebug() << "wa haha ";
}
然后在主线程的构造函数中用connect连接:
connect(&myCompThread,SIGNAL(postErrorMessage(const QStrin&)),this,SLOT(showErrorMessage(const QString&)));
 

  非常感谢。。。
离线kenangogogo

只看该作者 3楼 发表于: 2008-09-05
  怎么没有人理我???
我的问题太幼稚吗???
离线kenangogogo

只看该作者 4楼 发表于: 2008-09-05
               
谁来帮帮我??
离线water_wf

只看该作者 5楼 发表于: 2008-09-05
可以线不用自定义信号,你上面不是说进度条的消息得不到呢,还是都得不到
离线kenangogogo

只看该作者 6楼 发表于: 2008-09-05
好的,可能有点多,非常感谢你的耐心。。。
顺便问一句,这个论坛怎么给分。。。[

这是计算线程的头文件和实现文件:[/size]
#ifndef COMPTHREAD_H
#define COMPTHREAD_H

#include <QThread>
#include <QMutex>
#include <QFile>
#include <QDir>
#include <QString>
#include <QDataStream>
#include <QtDebug>
#include <QWaitCondition>



class CompThread : public QThread
{
    Q_OBJECT

public:
    CompThread(QObject *parent = 0);
    ~CompThread();
    void setSourceFilePath(const QString& sourceFilePath);
    void setReviseFileDir(const QString& reviseFileDir);
   
signals:
    void progressBarMaximumValue(qint32 maxValue);
    void progressBarIncreased(qint32 currentValue);
    void postErrorMessage(const QString& errorMessage);

protected:
    void run();

private:
    QString m_SourceFilePath;
    QString m_ReviseFileDir;
    QWaitCondition compTime;
    QMutex mutex;
};

#endif // COMPTHREAD_H




#include "compthread.h"

CompThread::CompThread(QObject *parent)
    : QThread(parent)
{
    m_SourceFilePath = QString::null;//记住这个函数,比较有用。
    m_ReviseFileDir = QString::null;
}

CompThread::~CompThread()
{
}

void  CompThread::run()//execute the main task which consumed a lot of time .
{
    mutex.lock();
    if(m_SourceFilePath.isEmpty() || m_ReviseFileDir.isEmpty())
    {
        emit postErrorMessage("didn't select the source file path or the revise files dir .");
        compTime.wait(&mutex);
        mutex.unlock();
    }
       
    QFile sourceFile(m_SourceFilePath);
    if(!sourceFile.open(QIODevice::ReadOnly))
        emit postErrorMessage("Can not open the source file .");
    QDataStream sourceFileStream(&sourceFile);
    sourceFileStream.setByteOrder(QDataStream::LittleEndian);//本机可是intel处理器,字节顺序是小字节的,fuck,搞了好久。

    QDir reviseFileDir(m_ReviseFileDir);
    reviseFileDir.setFilter(QDir::Files);
    QDir::setCurrent(m_ReviseFileDir);//指定当前路径为修改文件目录。
    int NUM = reviseFileDir.count();
    QFile* reviseFile = new QFile[NUM];
    if(reviseFile == NULL)
        emit postErrorMessage("Failture to allocate memory .");
    QDataStream* reviseFileStream = new QDataStream[NUM];
    if(reviseFileStream == NULL)
        emit postErrorMessage("Failture to allocate memory .");
    for(int i = 0;i < NUM;i++)//指定欲修改的各文件到相关的QFile和QDataStream上。
    {
        reviseFile.setFileName(reviseFileDir);
        if(!reviseFile.open(QIODevice::ReadWrite))
            emit postErrorMessage(QString("Can not open %1 .").arg(reviseFileDir));
        reviseFileStream.setDevice(&reviseFile);
        reviseFileStream.setByteOrder(QDataStream::LittleEndian);
    }


    //找到各文件的最大起始cmp。
    qint32* cmp = new qint32[NUM+1];
    if(cmp == NULL)
        emit postErrorMessage("Failture to allocate memory .");
    qint16 sourceFileSampleNum = 0;//定义源文件采样点
    qint16 reviseFileSampleNum = 0;//修改文件采样点
    sourceFile.seek(3220);//定位到源文件采样点字节处。
    sourceFileStream >> sourceFileSampleNum;
    reviseFile[0].seek(3220);//因为修改文件的各个采样点都一样,所以这里只需读一个。
    reviseFileStream[0] >> reviseFileSampleNum;

    sourceFile.seek(3620);//定位到sourcefile的cmp字节处。
    sourceFileStream >> cmp[0];//读取sourcefile的第一个cmp到cmp[0]
    for(int j = 0; j < NUM;j++)
    {
        reviseFile[j].seek(3620);//定位到各revisefile的cmp字节处
        reviseFileStream[j] >> cmp[j+1];//读各revisefile的cmp到cmp数组中。
    }//cmp[]表示每个文件的起始cmp号。

    if(cmp[0] > cmp[1])
        emit postErrorMessage("wrong source file .");
    qint32 sourceFileTraceLen = sourceFileSampleNum*4 + 240;//sourceFileTraceLen记录源文件一道的字节数。
    qint32 reviseFileTraceLen = reviseFileSampleNum*4 + 240;//reviseFileTraceLen记录修改文件一道的字节数。





    /*------------------------------------------------开始修改野外记录号----------------------------------*/


    //把小循环放在外面:
    bool find = 0;//指示是否在源文件中找到其始CMP。
    const qint32 startCMP = cmp[1];//设置起始CMP。
    qint64 sourceStartPos = 3620;//定义源文件起始点。
    while(!sourceFileStream.atEnd())//将源文件的当前指针位置定于startCMP上。
    {
        if(cmp[0] != startCMP)
        {
            sourceStartPos = sourceStartPos + sourceFileTraceLen;
            sourceFile.seek(sourceStartPos);
            sourceFileStream >> cmp[0];
        }else
        {
            find = 1;//找到
            break;
        }
    }
    if(!find)
        emit postErrorMessage(QString("Error: CMP %1 doesn't exist in the source file")
                             .arg(startCMP));


    qint32 finalTraceNum = (reviseFile[0].size() - 3600)/reviseFileTraceLen;//the total trace numbers of a revise file.
    qint32 currentSourceCMP;//定义当前源文件的CMP
    qint64 currentSourceSeekPos;//定义当前源文件的指针位置变量。
    qint32* currentReviseCMP = new qint32[NUM];//定义当前修改文件的CMP
    if(currentReviseCMP == NULL)
        emit postErrorMessage("Failture to allocate memory .");
    qint64 currentReviseSeekPos;//定义当前修改文件指针变量


    //emits progressBar signal (maxValue).
    emit progressBarMaximumValue(NUM * finalTraceNum);
   



    for(int num = 0;num < NUM;num++)//一个num代表一个文件
    {
        currentSourceCMP = startCMP;//每个文件开始时,当前源文件CMP设为起始CMP
        currentSourceSeekPos = sourceStartPos;//每个文件开始时,当前源文件指针位置设为起始起始CMP对应位置
        currentReviseCMP[num] = startCMP;//每个文件开始时,当前修改文件CMP设为起始CMP
        currentReviseSeekPos = 3620;//每个文件开始时,当前修改文件指针设为第一道CMP位置

        for(int trace = 0;trace < finalTraceNum; trace++)
        {
            qint32 deltaTrace = currentSourceCMP - currentReviseCMP[num];//记录源文件当前CMP与revise文件当前CMP的差异。
            if(deltaTrace > 0)
            {
                emit postErrorMessage(QString("Error: %1 traces were missed in the source file .")
                                     .arg(deltaTrace));
            }else
            {
                qint32 fieldRecordNum;//definate the field record number.
                //move the source file's file pointer to the currentReviseCMP[num].
                currentSourceSeekPos = currentSourceSeekPos + (-1)*deltaTrace*sourceFileTraceLen;
                sourceFile.seek(currentSourceSeekPos - 12);//position to the field record number.
                sourceFileStream >> fieldRecordNum;//read the field record number.
                reviseFile[num].seek(currentReviseSeekPos - 12);
                reviseFileStream[num] << fieldRecordNum;//write the number to the reviseFile[num].
            }

            currentSourceSeekPos = currentSourceSeekPos + sourceFileTraceLen;//move to the next trace int source file;
            sourceFile.seek(currentSourceSeekPos);
            sourceFileStream >> currentSourceCMP;//read a new source current CMP .
            currentReviseSeekPos = currentReviseSeekPos + reviseFileTraceLen;//move to the next trace in revise file
            reviseFile[num].seek(currentReviseSeekPos);
            reviseFileStream[num] >> currentReviseCMP[num];//read a new revise current CMP .

            //emits the progressBar's "increased" signal .
            emit progressBarIncreased(trace + finalTraceNum * num);
        }
    }
  //emits the last increased value .
    emit progressBarIncreased(NUM * finalTraceNum);


    /*-------------------野外记录号修改结束(THANKS)--------------------*/

}



void CompThread::setSourceFilePath(const QString &sourceFilePath)
{
    m_SourceFilePath = sourceFilePath;
}

void CompThread::setReviseFileDir(const QString &reviseFileDir)
{
    m_ReviseFileDir = reviseFileDir;
}


这是GUI的

#ifndef SEGYREVISE_H
#define SEGYREVISE_H

#include <QtGui/QWidget>
#include "ui_segyrevise.h"
#include "compthread.h"
#include <QFileDialog>
#include <QString>
#include <QErrorMessage>
#include <QWaitCondition>
#include <QMutex>

class SegyRevise : public QWidget
{
    Q_OBJECT

public:
    SegyRevise(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~SegyRevise();

public slots:
    void on_sourcePathBrowseButton_clicked();
    void on_reviseDirBrowseButton_clicked();
    void setProgressBarMaxValue(qint32 maxValue);
    void setProgressBarValue(qint32 currentValue);
    void showErrorMessage(const QString& errorMessage);

private:
    Ui::SegyRevise ui;
    CompThread myCompThread;
    //QWaitCondition wait;
    //QMutex mainMutex;
};

#endif // SEGYREVISE_H


#include "segyrevise.h"

SegyRevise::SegyRevise(QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags)
{
    ui.setupUi(this);
    ui.progressBar->setVisible(false);
    connect(ui.revisePushButton,SIGNAL(clicked()),&myCompThread,SLOT(start()));
    connect(&myCompThread,SIGNAL(progressBarMaxValue(qint32)),this,SLOT(setProgressBarMaxValue(qint32)));
    connect(&myCompThread,SIGNAL(progressBarIncreased()),this,SLOT(setProgressBarValue()));
    qRegisterMetaType<QString>("QString");
    connect(&myCompThread,SIGNAL(postErrorMessage(const QStrin&)),this,SLOT(showErrorMessage(const QString&)));
}

SegyRevise::~SegyRevise()
{

}


// The following : all about the slots
void SegyRevise::on_sourcePathBrowseButton_clicked()
{
    QString temp = QFileDialog::getOpenFileName(this,
                   tr("Open source file"),QString(),
                   tr("*.sgy"));
    ui.sourcePathLineEdit->setText(temp);
    myCompThread.setSourceFilePath(temp);

}

void SegyRevise::on_reviseDirBrowseButton_clicked()
{
    QString temp = QFileDialog::getExistingDirectory(this,
                   tr("Open revise file dir"));
    ui.reviseDirLineEdit->setText(temp);
    myCompThread.setReviseFileDir(temp);
}

void SegyRevise::setProgressBarMaxValue(qint32 maxValue)
{
    ui.progressBar->setVisible(true);
    ui.progressBar->setMinimum(0);
    ui.progressBar->setMaximum(maxValue);
}

void SegyRevise::setProgressBarValue(qint32 currentValue)
{
    ui.progressBar->setValue(currentValue);
}
void SegyRevise::showErrorMessage(const QString& errorMessage)
{
    QErrorMessage error;
    error.showMessage(errorMessage);
    //qDebug() << "wa haha ";
}

由designer生成ui 代码没有贴,如果需要,我再弄上来。。。。
离线water_wf

只看该作者 7楼 发表于: 2008-09-06
if(m_SourceFilePath.isEmpty() || m_ReviseFileDir.isEmpty())
    {
        emit postErrorMessage("didn't select the source file path or the revise files dir .");
        compTime.wait(&mutex);
        mutex.unlock();
    }
//没仔细看,不过你这里肯定有问题,什么时候唤醒呢,QWaitCondition 需要唤醒的wakeOne or wakeAll,
这其他地方设置 m_SourceFilePath  m_ReviseFileDir后,执行compTime.wakeOne()
然后在run内继续判断是否被设置
离线fly_sunshine

只看该作者 8楼 发表于: 2008-09-10
楼主这个文问题解决了没有啊,遇到了同样的问题,能不能讲下解决的办法啊
离线blusherbear

只看该作者 9楼 发表于: 2008-09-10
楼主检查一下这段代码:
SegyRevise::SegyRevise(QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags)
{
    ui.setupUi(this);
    ui.progressBar->setVisible(false);
    connect(ui.revisePushButton,SIGNAL(clicked()),&myCompThread,SLOT(start()));
    connect(&myCompThread,SIGNAL(progressBarMaxValue(qint32)),this,SLOT(setProgressBarMaxValue(qint32)));
    connect(&myCompThread,SIGNAL(progressBarIncreased()),this,SLOT(setProgressBarValue()));
    qRegisterMetaType<QString>("QString");
    connect(&myCompThread,SIGNAL(postErrorMessage(const QStrin&)),this,SLOT(showErrorMessage(const QString&)));
}
其中
connect(&myCompThread,SIGNAL(progressBarIncreased()),this,SLOT(setProgressBarValue()));
这个语句中signal与slot的参数似乎不对,应该为:
connect(&myCompThread,SIGNAL(progressBarIncreased(qint32)),this,SLOT(setProgressBarValue(qint32)));???
再就是楼主留意一下Qt的文档,QProgressBar的取值范围似乎是有限的。
离线x-planet

只看该作者 10楼 发表于: 2008-11-10
我也遇到类似问题 关注
快速回复
限100 字节
 
上一个 下一个