首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

MFC 多線程浮點數組計算:結果自動保存與錯誤恢復機制

     編輯:程式設計疑難解答

需求分析

  • 多線程並行計算浮點數組。
  • 計算結果需自動持久化保存。
  • 發生錯誤時自動恢復並繼續計算(斷點續傳)。

核心架構設計


// 任務單元:代表一個可獨立計算、保存、恢復的工作塊
struct ComputeTask {
    int taskId;                 // 全局唯一 ID
    int startIndex, endIndex;   // 數組切片範圍
    std::vector<double> inputData;  // 輸入數據 (或共享內存指針+偏移)
    std::vector<double> resultData; // 計算結果
    enum Status { PENDING, RUNNING, COMPLETED, FAILED } status;
    int retryCount;
    std::string errorMsg;
    
    // 序列化保存到文件
    void save(const std::string& filename) const;
    // 從文件恢復
    static ComputeTask load(const std::string& filename);
};

持久化策略

方案一:文件系統 (簡單、可靠)

  • 每個 Task 完成後立即寫入獨立文件:task_.bin (二進制) 或 .json。
  • 維護一個進度清單文件 progress.json:記錄所有 Task ID、狀態、文件路徑、時間戳。
  • 啟動時讀取 progress.json,跳過 COMPLETED 任務,重試 FAILED 任務。

方案二:數據庫 (SQLite/Access/PostgreSQL)

  • 表結構:Tasks(id, start_idx, end_idx, status, result_blob, error, created_at, updated_at)。
  • 事務保證原子性:更新狀態 + 寫入結果在同一事務。
  • 適合多進程/分布式擴展,查詢彙總方便。

方案三:內存映射文件

  • 大數組直接 mmap / CreateFileMapping 到文件,計算結果直接寫入映射區。
  • OS 自動處理頁交換,斷電數據不丟失(需 FlushViewOfFile)。
  • 最高性能,但編程複雜度高。

錯誤恢復機制

// 工作線程主循環
UINT ComputeThread(LPVOID pParam) {
    ComputeManager* mgr = (ComputeManager*)pParam;
    
    while (true) {
        ComputeTask task = mgr->getNextPendingTask(); // 線程安全獲取
        if (task.taskId == -1) break; // 無任務退出
        
        task.status = ComputeTask::RUNNING;
        mgr->updateTaskStatus(task); // 持久化狀態
        
        try {
            // 核心計算邏輯
            task.resultData = computeSlice(task.inputData);
            task.status = ComputeTask::COMPLETED;
        } catch (const std::exception& e) {
            task.status = ComputeTask::FAILED;
            task.errorMsg = e.what();
            task.retryCount++;
            
            if (task.retryCount <= MAX_RETRY) {
                // 重新入隊重試
                mgr->requeueTask(task);
                Sleep(RETRY_DELAY_MS);
                continue;
            }
        }
        
        // 保存結果 (成功或最終失敗)
        task.save(mgr->getTaskFilePath(task.taskId));
        mgr->updateTaskStatus(task);
    }
    return 0;
}

MFC 集成要點

  • 使用 AfxBeginThread 創建工作線程,傳遞管理器指針。
  • 共享數據結構需 CCriticalSection / CMutex 保護。
  • UI 線程通過 PostMessage(WM_USER_PROGRESS, ...) 更新進度條/列表。
  • 主對話框/視圖類持有 ComputeManager*,析構時發送停止信號、等待線程結束、彙總結果。

斷點續傳完整流程

  1. 啟動:讀取 progress.json → 重建任務隊列 → 標記 COMPLETED 任務為跳過,FAILED 重置為 PENDING (重試計數保留)。
  2. 運行:線程池消費隊列 → 計算 → 異常捕獲重試 → 保存結果文件 → 更新進度文件。
  3. 中斷:收到停止信號 → 線程完成當前 Task 保存 → 更新進度 → 退出。
  4. 恢復:重新啟動 → 同步驟 1,無縫銜接。

關鍵代碼片段:進度文件管理

// progress.json 結構
{
  "version": 1,
  "totalTasks": 100,
  "completed": 45,
  "tasks": [
    {"id": 0, "status": "COMPLETED", "file": "task_0.bin", "time": "2024-01-15T10:00:00Z"},
    {"id": 1, "status": "FAILED", "retry": 2, "error": "div by zero", "file": "", "time": "..."},
    ...
  ]
}

// 讀取/寫入封裝 (使用 nlohmann/json 或 MFC CJsonObject)
void ComputeManager::loadProgress() { /* 解析 JSON 重建隊列 */ }
void ComputeManager::saveProgress() { /* 序列化寫入文件 */ }

總結

「自動保存 + 錯誤恢復」核心在於將計算拆解為可獨立持久化的 Task,配合進度元數據文件/數據庫記錄狀態。MFC 多線程下,使用文件系統或 SQLite落地結果,線程池 + 任務隊列 + 重試邏輯實現斷點續傳,UI 通過消息泵異步更新進度。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved