首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

多線程編程最佳實踐:以 MD5 暴力破解為例的任務分發、無鎖設計與效能調優

     編輯:關於C語言

場景:MD5 暴力破解

  • 字符集:26 個小寫字母
  • 長度:1~8 位
  • 總組合數:Σ 26^i (i=1..8) ≈ 2171 億
  • 目標:利用多核 CPU 縮短破解時間

四種方案對比

方案描述同步機制優點缺點
1. 共享單一生成器多線程輪流取下一個候選串Mutex / Interlocked候選序列連續鎖爭用極大,4 線程比單線程慢 8 倍
2. 靜態均分任務啟動前將空間均分 N 份無無同步開銷負載不均,代碼難復用
3. 固定大小任務包預切分任務包,線程動態領取領取時互斥負載較均需調優包大小,邏輯複雜
4. 動態任務竊取 (採用)線程按需從全局隊列取固定批次原子隊列操作負載自動均衡、邏輯簡潔、高復用批次大小需調優

方案 4 核心設計

// 全局任務隊列 (環形緩衝區 + 原子索引)
typedef struct { uint64_t start, end; } Task;
Task task_queue[TASK_QUEUE_SIZE];
atomic_size_t head = 0, tail = 0;

// 生產者:主線程按批次切分總空間入隊
void producer(uint64_t total, uint64_t batch) {
    for (uint64_t s = 0; s < total; s += batch) {
        uint64_t e = min(s + batch, total);
        size_t idx = atomic_fetch_add(&tail, 1) % TASK_QUEUE_SIZE;
        task_queue[idx] = (Task){s, e};
    }
}

// 消費者:工作線程循環取任務
void *worker(void *arg) {
    Task t;
    while (1) {
        size_t h = atomic_load(&head);
        size_t t_idx = atomic_load(&tail);
        if (h == t_idx) break; // 隊列空
        if (atomic_compare_exchange_weak(&head, &h, (h + 1) % TASK_QUEUE_SIZE)) {
            t = task_queue[h];
            crack_range(t.start, t.end); // 核心破解邏輯
        }
    }
    return NULL;
}

關鍵優化點

  1. 批次大小:太小 → 原子操作開銷大;太大 → 負載不均。經驗值:總空間 / (核心數 * 100)
  2. 無鎖隊列:C11 atomic_* 或 GCC 内建 __sync_*,避免 Mutex 內核切換
  3. 仿射變換生成候選:將線性索引 0..N-1 映射為字符串,無需字串操作,純整數運算
  4. 早期退出:找到密碼設置全局標誌,其他線程檢測後退出
  5. CPU 親和性:pthread_setaffinity_np 綁核,減少緩存失效

實測數據 (4 核 3.4GHz)

方案 4 (3 線程) 破解 ddzzzz (MD5) 僅需 4641ms,最優。

代碼復用性展示

同一框架僅替換 crack_range 即可應用於:

  • 密碼破解 (MD5, SHA, Bcrypt)
  • 大數據篩選 (素數、哈希碰撞)
  • 參數空間搜索 (超參數調優)
  • 圖像/視頻幂并行處理

下載與交流

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
線程數耗時加速比
1~16 小時1.0x
2~8.5 小時1.88x
3~5.8 小時2.76x
4~4.3 小時3.72x