遷移到子線程的變量應用處置

在寫Qt過程中,目前會遇到大量數據處理,數據量200W以上,如果將處理數據操作在主線程中進行,會導致UI界面凍結,影響用戶體驗,所以將處理數據的過程遷移到子線程中是良好的處理手段,一般處理數據的對象都會定義爲指針類型。代碼如下:

/***************************************************************************
     @date     2021-02-25
     @author   qiaowei
     @contact  [email protected]
     @version  1.0
     @brief    子線程,運行file_process_變量
    ***************************************************************************/
    QThread file_process_thread_;

    File_process* file_process_;

如果將對象遷移到子線程的步驟延後,就會有創建指針,遷移到子線程,創建指針,未遷移到子線程兩種情況。代碼如下:


void File_manager::start_thread(QThread& thread, QObject *process)
{
    if ( !thread.isRunning()) {

        process->moveToThread(&thread);
        connect(&thread, &QThread::finished, process, &QObject::deleteLater);
        thread.start();
    }
}

void File_manager::sl_open_file_to_split_data()
{
    QStringList opened_files = QFileDialog::getOpenFileNames();

    if (opened_files.isEmpty()) {
        return;
    }

    // 將處理文件數據對象遷入子線程,啓動子線程
    start_thread(file_process_thread_, file_process_);

    emit si_files_name_of_split_data(opened_files);
}

void File_manager::sl_read_data_from_file()
{
    QStringList opened_files = QFileDialog::getOpenFileNames();

    if (opened_files.isEmpty()) {
        return;
    }

    // 將處理文件數據對象遷入子線程,啓動子線程
    start_thread(file_process_thread_, file_process_);

    emit si_files_name_of_readed_data(opened_files);
}

所以,如何避免內存泄漏,正確處理好指針變量,應該在類的析構函數中有所考量。Qt官方文檔在構造函數中直接啓動子線程,未將子線程延後:

class Controller : public QObject
 {
     Q_OBJECT
     QThread workerThread;
 public:
     Controller() {
         Worker *worker = new Worker;
         worker->moveToThread(&workerThread);
         connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
         connect(this, &Controller::operate, worker, &Worker::doWork);
         connect(worker, &Worker::resultReady, this, &Controller::handleResults);
         workerThread.start();
     }
     ~Controller() {
         workerThread.quit();
         workerThread.wait();
     }
 public slots:
     void handleResults(const QString &);
 signals:
     void operate(const QString &);
 };

在處理延後子線程數據時,要考慮創建的指針對象存在的線程,如果在主線程,說明沒有啓動子線程,直接delete即可,如果不在主線程中,則不用手動處理,調用子線程方法,系統會自動處理。我的處理代碼如下:

File_manager::~File_manager()
{
    // 用戶沒有點擊打開文件或拆分數據按鈕,file_process_沒有遷移到file_process_thread_線程中,需手動
    // 釋放資源
    if (file_process_->thread() == thread()) {
        delete file_process_;
        file_process_ = nullptr;
    }

    file_process_thread_.quit();
    file_process_thread_.wait();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章