c++手撕線程池

C++手撕線程池


#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>#define LL_ADD(item, list) do{			 \item->prev = NULL;					 \item->next = list;					 \if (list != NULL) list-> prev = item;\list = item;						 \
} while(0) #define LL_REMOVE(item, list) do{ 								 \if(item-> prev != NULL) item -> prev -> next = item -> next; \if(item-> next != NULL) item -> next -> prev = item -> prev; \	if(list == item) list = item -> next;						 \item-> prev = item -> next = NULL;   						 \
} while(0) struct NJOB
{void (*func)(void *arg); // 回調函數每一個任務需要那些參數void *user_data; // 任務執行需要什么參數struct NJOB *prev;struct NJOB *next; //雙向鏈表 隊列
};
// 若干任務組織到一起struct NWORKER
{pthread_t id; // 每一個worker相當于一個線程int terminate;struct NMANAGER *pool;struct NWORKER *prev;struct NWORKER *next;};typedef struct NMANAGER
{pthread_mutex_t mtx; //用于抓取任務pthread_cond_t cond; //當任務隊列為空的時候做的struct NJOB *jobs;struct NWORKER *workers;	
} nThreadPool;void *thread_cb(void *arg)
{struct NWORKER *worker = (struct NWORKER*) arg;// 線程從隊列里面拿到一個任務去執行// 線程去爭奪隊列里面的資源// 不斷去執行,是一個循環while(1){// 具體內容是由job的回調函數決定的pthread_mutex_lock(&worker->pool->mtx);while(worker->pool->jobs == NULL){if (worker-> terminate) break;pthread_cond_wait(&worker->pool->cond, &worker->pool-> mtx);}// 如果job為空就讓線程休息// 檢查終止條件if (worker->terminate) {pthread_mutex_unlock(&worker->pool->mtx);break;}struct NJOB *job = worker-> pool-> jobs;if(job != NULL){LL_REMOVE(job, worker-> pool-> jobs); // 取出頭結點}pthread_mutex_unlock(&worker->pool->mtx);// 執行任務if (job != NULL && job -> func != NULL){job-> func(job->user_data);// 注意:這里不釋放job,由任務函數負責釋放user_datafree(job);// 釋放任務結構體本身}}
}// sdkint nThreadPoolCreate(nThreadPool *pool, int numWorkers)
{// if (numWorkers < 1) numWorkers = 1;if (pool == NULL) return -1;memset(pool, 0, sizeof(nThreadPool));//pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;memcpy(&pool->mtx, &blank_mutex, sizeof(pthread_mutex_t));// pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;memcpy(&pool->cond, &blank_cond, sizeof(pthread_cond_t));//int i = 0;for(i =0;i<numWorkers;i++){struct NWORKER *worker = (struct NWORKER *)malloc(sizeof(struct NWORKER));if (worker == NULL){perror("malloc");return -2;}memset(worker, 0 ,sizeof(struct NWORKER) );worker->pool = pool;pthread_create(&worker->id, NULL, thread_cb,worker);LL_ADD(worker, pool->workers);}return 0;
}int nThreadPoolDestroy(nThreadPool *pool)
{if(pool == NULL)return -1;// 設置所有worker的終止標志struct NWORKER *worker = pool-> workers;while (worker != NULL){worker->terminate = 1;worker = worker -> next;}// 廣播條件變量喚醒所有線程pthread_mutex_lock(&pool->mtx);pthread_cond_broadcast(&pool->cond);pthread_mutex_unlock(&pool->mtx);// 等待所有worker線程退出worker = pool->workers;while (worker != NULL) {pthread_join(worker->id, NULL);struct NWORKER *next = worker->next;free(worker);worker = next;}// 銷毀互斥鎖和條件變量pthread_mutex_destroy(&pool-> mtx);pthread_cond_destroy(&pool->cond);// 清空任務隊列(如果有剩余任務)struct NJOB *job = pool->jobs;while (job!= NULL){struct NJOB *next = job->next;free(job);job = next;}// 重置線程池狀態pool-> workers = NULL;pool->jobs = NULL;return 0;}int nThreadPoolPushTask(nThreadPool *pool, struct NJOB *job)
{//如何往線程池丟任務// 往隊列里面加一個節點(job)// 同時通知一個worker(線程)// 因為線程都在條件等待pthread_mutex_lock(&pool->mtx);LL_ADD(job, pool->jobs);pthread_cond_signal(pool->cond);pthread_mutex_unlock(&pool->mtx);
}// // 測試函數
void debug_test()
{nThreadPool pool;const int NUM_THREADS = 10;const int NUM_TASKS = 1000;printf("Creating thread pool with %d workers...\n", NUM_THREADS);if (nThreadPoolCreate(&pool, NUM_THREADS) != 0) {fprintf(stderr, "Failed to create thread pool\n");return;}printf("Adding %d tasks to the pool...\n", NUM_TASKS);srand(time(NULL));for (int i = 0; i < NUM_TASKS; i++) {struct NJOB *job = (struct NJOB *)malloc(sizeof(struct NJOB));TaskData *data = (TaskData *)malloc(sizeof(TaskData));data->task_id = i;data->value = rand() % 100; // 隨機值0-99job->func = task_function;job->user_data = data;nThreadPoolPushTask(&pool, job);}// 等待所有任務完成printf("Waiting for tasks to complete...\n");sleep(3); // 簡單等待3秒// 銷毀線程池printf("Destroying thread pool...\n");nThreadPoolDestroy(&pool);printf("All done!\n");
}#if 1  //#if 0是完美注釋 #if 1即可運行
int main()
{debug_test();return 0;
}
#endif

互斥鎖

互斥鎖(Mutex)詳解

互斥鎖(Mutual Exclusion Lock,簡稱 Mutex)是多線程編程中用于保護共享資源不被同時訪問的核心同步機制。它的核心作用是確保在任何給定時刻,只有一個線程可以訪問被保護的資源或代碼區域。

互斥鎖的核心概念

1. 基本工作原理

線程1請求鎖
鎖空閑?
獲取鎖
等待
訪問共享資源
釋放鎖

2. 關鍵特性

  • 互斥性:同一時刻只允許一個線程持有鎖
  • 原子性:鎖的獲取和釋放操作是原子的(不可中斷)
  • 阻塞性:未獲得鎖的線程會進入等待狀態
  • 所有權:鎖由獲取它的線程獨占持有

互斥鎖的使用場景

場景類型示例互斥鎖的作用
數據競爭多個線程訪問同一變量防止并發修改導致數據不一致
臨界區保護文件I/O操作確保操作序列的完整性
資源管理數據庫連接池控制有限資源的分配
狀態同步緩存更新機制保持狀態的一致性

互斥鎖的操作原語(以POSIX為例)

基本操作流程

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 線程函數
void* thread_func(void* arg) {pthread_mutex_lock(&mutex);    // 1. 嘗試獲取鎖// 臨界區代碼 - 安全訪問共享資源pthread_mutex_unlock(&mutex);  // 2. 釋放鎖return NULL;
}

鎖的類型

鎖類型特性適用場景
普通鎖默認類型,不可遞歸獲取簡單臨界區保護
遞歸鎖同一線程可多次獲取遞歸函數或可重入代碼
檢錯鎖檢測死鎖和重復鎖定調試階段
自適應鎖優化自旋等待時間高競爭環境

互斥鎖的底層實現原理

1. 硬件支持

現代CPU提供原子指令實現鎖:

  • Test-and-Set 指令
  • Compare-and-Swap (CAS) 指令
  • Load-Link/Store-Conditional (LL/SC) 指令

2. 用戶空間實現(Futex)

Linux的Futex(Fast Userspace Mutex)機制:

// 簡化版Futex實現
void futex_lock(int* lock) {while (atomic_compare_exchange(lock, 0, 1) != 0) {// 鎖已被占用,進入內核等待syscall(SYS_futex, lock, FUTEX_WAIT, 1, NULL, NULL, 0);}
}void futex_unlock(int* lock) {atomic_set(lock, 0);// 喚醒等待線程syscall(SYS_futex, lock, FUTEX_WAKE, 1, NULL, NULL, 0);
}

3. 內核支持

當鎖競爭激烈時,操作系統內核介入:

  1. 將等待線程放入阻塞隊列
  2. 在鎖釋放時調度等待線程
  3. 處理優先級反轉問題

互斥鎖的使用注意事項

1. 避免死鎖

死鎖產生的四個必要條件:

  1. 互斥條件
  2. 持有并等待
  3. 不可搶占
  4. 循環等待

預防策略

  • 固定加鎖順序
  • 使用超時機制
  • 死鎖檢測算法

2. 性能優化

技術描述效果
細粒度鎖為不同資源使用獨立鎖減少競爭
讀寫鎖區分讀/寫操作提高讀并發性
無鎖編程CAS操作替代鎖完全避免鎖開銷
鎖分段將大資源分段加鎖減少熱點競爭

3. 最佳實踐

// 推薦用法:RAII模式(資源獲取即初始化)
void critical_section() {LockGuard guard(&mutex); // 構造時加鎖// 臨界區代碼// ...} // 析構時自動解鎖(即使發生異常)

互斥鎖與其他同步機制對比

機制特點適用場景
互斥鎖獨占訪問,簡單直接通用臨界區保護
自旋鎖忙等待,不放棄CPU鎖持有時間極短
信號量計數器,控制訪問數量資源池管理
條件變量基于條件等待/通知生產者-消費者模式
讀寫鎖區分讀/寫訪問權限讀多寫少場景

互斥鎖在不同語言中的實現

C++ (std::mutex)

#include <mutex>std::mutex mtx;void safe_increment(int& value) {std::lock_guard<std::mutex> lock(mtx);value++;
}

Java (synchronized)

public class Counter {private int value;private final Object lock = new Object();public void increment() {synchronized(lock) {value++;}}
}

Python (threading.Lock)

import threadinglock = threading.Lock()
counter = 0def increment():global counterwith lock:counter += 1

互斥鎖的性能考量

性能指標

  • 獲取延遲:從請求到獲取鎖的時間
  • 吞吐量:單位時間處理的操作數
  • 可擴展性:隨著線程數增加的性能變化

優化策略

  1. 減少臨界區大小:最小化加鎖代碼范圍
  2. 使用本地副本:在臨界區外準備數據
  3. 鎖消除:分析確定不需要的鎖
  4. 鎖粗化:合并相鄰的鎖操作

總結

互斥鎖是并發編程的基石,核心價值在于:

  • 提供線程安全的共享資源訪問
  • 確保數據一致性
  • 維護程序正確性

正確使用互斥鎖需要:

  1. 精確識別需要保護的共享資源
  2. 保持臨界區盡可能短小
  3. 建立一致的加鎖順序
  4. 使用RAII模式管理鎖生命周期
  5. 在高競爭場景考慮替代方案

理解互斥鎖的底層原理和最佳實踐,是構建高性能、高可靠性并發系統的關鍵基礎。

C++程序從編譯到變為.exe文件發生了什么

將 C++ 源代碼編譯為 Windows 的 .exe 文件是一個多階段的復雜過程,涉及多個工具和轉換步驟。以下是詳細的編譯過程:


完整的編譯流程

源代碼 .cpp
預處理器
編譯后的代碼 .ii
編譯器
匯編代碼 .s
匯編器
目標文件 .obj
鏈接器
可執行文件 .exe

詳細步驟解析

1. 預處理階段
  • 輸入.cpp 源文件 + 頭文件
  • 輸出:預處理后的源文件(通常為 .i.ii
  • 處理工具:預處理器(如 cpp 或編譯器內置預處理器)
  • 主要任務
    • 處理所有 # 開頭的預處理指令
      • #include → 插入頭文件內容
      • #define → 宏替換
      • #if/#ifdef → 條件編譯
    • 刪除所有注釋
    • 添加行號標記(用于調試)
    • 處理特殊宏(如 __LINE__, __FILE__

示例

// main.cpp
#include <iostream>
#define PI 3.14159int main() {std::cout << "Value: " << PI; // 注釋
}

↓ 預處理后 ↓

// 插入<iostream>的全部內容
namespace std { ... } // 約數千行代碼
#line 1 "main.cpp"
int main() {std::cout << "Value: " << 3.14159;
}

2. 編譯階段
  • 輸入:預處理后的源文件(.i
  • 輸出:匯編代碼文件(.s.asm
  • 處理工具:編譯器核心(如 g++ 的編譯前端)
  • 主要任務
    • 詞法分析:將源代碼分解為 token(關鍵字、標識符、運算符等)
    • 語法分析:構建抽象語法樹(AST)
    • 語義分析:類型檢查、作用域分析
    • 中間代碼生成:生成平臺無關的中間表示(如 LLVM IR)
    • 優化:進行各種優化(常量折疊、死代碼消除等)
    • 目標代碼生成:生成特定CPU架構的匯編代碼

生成的匯編示例(x86):

_main:push    ebpmov     ebp, esppush    OFFSET FLAT:.LC0 ; "Value: "push    3.14159call    __ZNSolsEf      ; std::cout<<float...

3. 匯編階段
  • 輸入:匯編代碼文件(.s
  • 輸出:目標文件(.obj.o
  • 處理工具:匯編器(如 asml
  • 主要任務
    • 將匯編指令轉換為機器碼
    • 生成目標文件格式(COFF 或 ELF)
    • 創建符號表(函數/變量地址)
    • 生成重定位信息(供鏈接器使用)

目標文件內容

  • 機器碼(二進制指令)
  • 數據段(初始化的全局變量)
  • BSS 段(未初始化的全局變量)
  • 符號表
  • 重定位記錄

4. 鏈接階段
  • 輸入:多個目標文件(.obj) + 庫文件(.lib
  • 輸出:可執行文件(.exe
  • 處理工具:鏈接器(如 ldlink.exe
  • 主要任務
    • 符號解析:解決跨文件的函數/變量引用
    • 重定位:合并所有目標文件,調整地址
    • 解析外部依賴:鏈接標準庫和第三方庫
    • 生成PE頭:創建Windows可執行文件結構

鏈接過程關鍵點

main.obj
鏈接器
math.obj
libstdc++.lib
program.exe

PE文件結構

├── DOS頭
├── PE文件頭
├── 節表
├── .text節(代碼)
├── .data節(初始化數據)
├── .rdata節(只讀數據)
├── .bss節(未初始化數據)
├── 導入表(依賴的DLL)
├── 資源節(圖標/版本信息)
└── 重定位表

完整工具鏈示例(GCC/MinGW)

# 1. 預處理(生成 main.ii)
g++ -E main.cpp -o main.ii# 2. 編譯(生成 main.s)
g++ -S main.ii -o main.s# 3. 匯編(生成 main.obj)
as main.s -o main.obj# 4. 鏈接(生成 program.exe)
g++ main.obj -o program.exe

或單步完成:

g++ main.cpp -o program.exe

關鍵概念詳解

1. 目標文件格式(COFF)
+-------------------+
| 文件頭            |
+-------------------+
| 節表              |
+-------------------+
| .text 節(代碼)  |
+-------------------+
| .data 節(數據)  |
+-------------------+
| .bss 節           |
+-------------------+
| 符號表            |
+-------------------+
| 重定位記錄        |
+-------------------+
| 調試信息          |
+-------------------+
2. PE文件結構
+-----------------------+
| DOS Stub              |
+-----------------------+
| PE Header             |
+-----------------------+
| Section Table         |
+-----------------------+
| .text (Code)          |
+-----------------------+
| .data (Initialized)   |
+-----------------------+
| .rdata (Constants)    |
+-----------------------+
| .idata (Imports)      |
+-----------------------+
| .rsrc (Resources)     |
+-----------------------+
| .reloc (Relocations)  |
+-----------------------+
3. 動態鏈接 vs 靜態鏈接
特性靜態鏈接動態鏈接
文件大小較大(包含所有依賴庫)較小(僅包含引用)
內存占用每個程序獨立占用內存共享庫節省內存
更新難度需重新編譯整個程序只需替換DLL文件
加載速度較快(無運行時加載開銷)較慢(需加載DLL)
示例-static 選項默認方式

常見問題診斷

1. 鏈接錯誤示例
undefined reference to `someFunction()'

原因

  • 函數聲明但未定義
  • 缺少鏈接庫
  • 名稱修飾不匹配(C vs C++)
2. 運行時錯誤
The procedure entry point could not be located in DLL

原因

  • 運行時DLL版本不匹配
  • 缺少依賴的DLL文件
  • 導出函數簽名變更
3. 調試信息
  • 編譯選項-g 生成調試信息
  • 文件格式
    • Windows:PDB(Program Database)
    • Linux:DWARF
  • 調試工具
    • Windows:WinDbg, Visual Studio Debugger
    • Linux:GDB

優化技術

源代碼
編譯器優化
鏈接時代碼生成 LTCG
PGO優化
  1. 編譯器優化

    • -O1:基礎優化(死代碼消除)
    • -O2:中級優化(循環展開)
    • -O3:激進優化(向量化)
  2. LTO(鏈接時優化)

    • 跨模塊內聯
    • 全局數據流分析
    • 使用:g++ -flto
  3. PGO(性能引導優化)

    帶插樁的編譯
    運行訓練數據
    收集性能數據
    使用數據重新編譯

總結

從 C++ 源代碼到 .exe 文件的轉換過程:

  1. 預處理:文本級轉換(宏/頭文件展開)
  2. 編譯:高級語言 → 匯編語言
  3. 匯編:匯編語言 → 機器碼(目標文件)
  4. 鏈接:合并目標文件 + 解析外部依賴 → 可執行文件

理解這個過程有助于:

  • 診斷編譯/鏈接錯誤
  • 優化構建性能
  • 進行底層調試
  • 創建高效的構建系統
  • 理解程序的內存布局和執行原理

pthread庫的常見用法以及使用函數

pthread_t
pthread_mutex_t
pthread_cond_t
pthread_mutex_lock
pthread_mutex_unlock
pthread_cond_wait
pthread_create
pthread_cond_broadcast
pthread_join
pthread_mutex_destroy
pthread_cond_destroy
pthread_cond_signal
pthread_mutex_lock
pthread_mutex_unlock
所有用到的pthread函數

pthread 庫詳解:常見用法與核心函數指南

一、pthread 庫概述

POSIX Threads (pthread) 是 Unix/Linux 系統上實現多線程編程的標準 API,提供了一套完整的線程創建、管理和同步機制。

核心特性:

  • 跨平臺:支持所有 POSIX 兼容系統(Linux, macOS, BSD 等)
  • 輕量級:線程創建和切換開銷遠小于進程
  • 共享內存:同一進程的線程共享地址空間
  • 豐富同步機制:提供互斥鎖、條件變量、讀寫鎖等

編譯鏈接:

gcc -pthread program.c -o program

二、核心線程管理函數

1. 線程創建 - pthread_create()

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void *), void *arg);
  • thread:輸出參數,存儲新線程ID
  • attr:線程屬性(NULL 為默認屬性)
  • start_routine:線程入口函數
  • arg:傳遞給線程函數的參數

示例

void *print_message(void *message) {printf("%s\n", (char*)message);return NULL;
}int main() {pthread_t tid;char *msg = "Hello from thread!";pthread_create(&tid, NULL, print_message, msg);pthread_join(tid, NULL); // 等待線程結束return 0;
}

2. 線程終止 - pthread_exit()

void pthread_exit(void *retval);
  • 用于線程內部主動退出
  • retval:線程返回值(可由 pthread_join 獲取)

3. 線程等待 - pthread_join()

int pthread_join(pthread_t thread, void **retval);
  • 阻塞調用線程,直到目標線程結束
  • retval:接收目標線程的返回值

4. 線程分離 - pthread_detach()

int pthread_detach(pthread_t thread);
  • 將線程標記為"可分離",結束后自動回收資源
  • 分離線程不能被 join

5. 線程取消 - pthread_cancel()

int pthread_cancel(pthread_t thread);
  • 請求取消指定線程
  • 目標線程需要設置取消點(如 sleep, wait 等)

三、線程同步機制

1. 互斥鎖 (Mutex)

// 初始化(靜態)
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 初始化(動態)
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);// 加鎖
int pthread_mutex_lock(pthread_mutex_t *mutex);// 嘗試加鎖(非阻塞)
int pthread_mutex_trylock(pthread_mutex_t *mutex);// 解鎖
int pthread_mutex_unlock(pthread_mutex_t *mutex);// 銷毀
int pthread_mutex_destroy(pthread_mutex_t *mutex);

使用模式

pthread_mutex_t lock;void *thread_func(void *arg) {pthread_mutex_lock(&lock);// 臨界區代碼pthread_mutex_unlock(&lock);return NULL;
}

2. 條件變量 (Condition Variables)

// 初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);// 等待條件
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);// 定時等待
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex,const struct timespec *abstime);// 發送信號(喚醒一個等待線程)
int pthread_cond_signal(pthread_cond_t *cond);// 廣播信號(喚醒所有等待線程)
int pthread_cond_broadcast(pthread_cond_t *cond);// 銷毀
int pthread_cond_destroy(pthread_cond_t *cond);

生產者-消費者示例

pthread_mutex_t lock;
pthread_cond_t cond;
int count = 0;void *producer(void *arg) {while(1) {pthread_mutex_lock(&lock);count++;printf("Produced: %d\n", count);pthread_cond_signal(&cond); // 喚醒消費者pthread_mutex_unlock(&lock);sleep(1);}
}void *consumer(void *arg) {while(1) {pthread_mutex_lock(&lock);while(count == 0) {pthread_cond_wait(&cond, &lock); // 等待生產}count--;printf("Consumed: %d\n", count);pthread_mutex_unlock(&lock);}
}

3. 讀寫鎖 (Read-Write Lock)

// 初始化
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;// 讀鎖定(共享)
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);// 寫鎖定(獨占)
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);// 解鎖
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

適用場景

  • 讀操作遠多于寫操作
  • 允許多個讀線程同時訪問

四、線程屬性控制

1. 初始化/銷毀屬性

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);

2. 常用屬性設置

// 設置分離狀態
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
// PTHREAD_CREATE_JOINABLE (默認) / PTHREAD_CREATE_DETACHED// 設置棧大小
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);// 設置調度策略
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
// SCHED_FIFO, SCHED_RR, SCHED_OTHER// 設置調度參數
int pthread_attr_setschedparam(pthread_attr_t *attr,const struct sched_param *param);

示例

pthread_attr_t attr;
pthread_attr_init(&attr);// 設置為分離線程
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);// 設置棧大小為2MB
pthread_attr_setstacksize(&attr, 2 * 1024 * 1024);pthread_t tid;
pthread_create(&tid, &attr, thread_func, NULL);pthread_attr_destroy(&attr);

五、線程特定數據 (Thread-Specific Data)

允許每個線程擁有自己的私有數據副本

// 創建鍵
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));// 刪除鍵
int pthread_key_delete(pthread_key_t key);// 設置鍵的值
int pthread_setspecific(pthread_key_t key, const void *value);// 獲取鍵的值
void *pthread_getspecific(pthread_key_t key);

示例

pthread_key_t tls_key;void destructor(void *value) {free(value);
}void init_tls() {pthread_key_create(&tls_key, destructor);
}void *thread_func(void *arg) {// 為每個線程分配私有數據int *data = malloc(sizeof(int));*data = pthread_self(); // 示例值pthread_setspecific(tls_key, data);// 獲取私有數據int *my_data = pthread_getspecific(tls_key);printf("Thread %lu: my data = %d\n", (unsigned long)pthread_self(), *my_data);return NULL;
}

六、高級同步機制

1. 屏障 (Barriers)

// 初始化
int pthread_barrier_init(pthread_barrier_t *barrier,const pthread_barrierattr_t *attr,unsigned int count);// 等待
int pthread_barrier_wait(pthread_barrier_t *barrier);// 銷毀
int pthread_barrier_destroy(pthread_barrier_t *barrier);

使用場景:多線程同步點,所有線程到達屏障前阻塞

2. 自旋鎖 (Spinlocks)

// 初始化
pthread_spinlock_t spinlock;
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);// 加鎖/解鎖
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);

特點:忙等待鎖,適用于鎖持有時間極短的場景

七、最佳實踐與常見陷阱

1. 線程安全設計原則

  • 優先使用不可變數據結構
  • 限制共享數據范圍
  • 使用RAII模式管理鎖
  • 避免鎖嵌套(如必須,保持固定順序)
  • 優先使用高級并發抽象(線程池、任務隊列)

2. 常見錯誤

// 錯誤1:返回棧上變量的指針
void *thread_func(void *arg) {int local = 42;return &local; // 錯誤!線程退出后局部變量被銷毀
}// 錯誤2:忘記解鎖
void critical_section() {pthread_mutex_lock(&lock);// 可能提前返回或拋出異常if(error) return; // 忘記解鎖!pthread_mutex_unlock(&lock);
}// 錯誤3:虛假喚醒處理不當
while(!condition) { // 必須用循環檢查條件pthread_cond_wait(&cond, &lock);
}

3. 調試技巧

  • 使用 gdbinfo threads 查看線程狀態
  • 使用 valgrind --tool=helgrind 檢測數據競爭
  • 添加調試日志(帶線程ID):
    printf("[Thread %lu] %s\n", (unsigned long)pthread_self(), message);
    

八、完整示例:線程池實現

#include <pthread.h>
#include <stdlib.h>#define THREAD_POOL_SIZE 4typedef struct {void (*task)(void *);void *arg;
} Task;typedef struct {pthread_mutex_t lock;pthread_cond_t task_cond;pthread_t threads[THREAD_POOL_SIZE];Task *task_queue;int queue_size;int queue_capacity;int shutdown;
} ThreadPool;void *worker_thread(void *arg) {ThreadPool *pool = (ThreadPool *)arg;while(1) {pthread_mutex_lock(&pool->lock);// 等待任務或關閉信號while(pool->queue_size == 0 && !pool->shutdown) {pthread_cond_wait(&pool->task_cond, &pool->lock);}if(pool->shutdown) {pthread_mutex_unlock(&pool->lock);pthread_exit(NULL);}// 取出任務Task task = pool->task_queue[--pool->queue_size];pthread_mutex_unlock(&pool->lock);// 執行任務task.task(task.arg);}return NULL;
}void thread_pool_init(ThreadPool *pool) {pthread_mutex_init(&pool->lock, NULL);pthread_cond_init(&pool->task_cond, NULL);pool->queue_capacity = 10;pool->queue_size = 0;pool->task_queue = malloc(pool->queue_capacity * sizeof(Task));pool->shutdown = 0;for(int i = 0; i < THREAD_POOL_SIZE; i++) {pthread_create(&pool->threads[i], NULL, worker_thread, pool);}
}void thread_pool_submit(ThreadPool *pool, void (*task)(void *), void *arg) {pthread_mutex_lock(&pool->lock);// 擴展任務隊列(如果需要)if(pool->queue_size == pool->queue_capacity) {pool->queue_capacity *= 2;pool->task_queue = realloc(pool->task_queue, pool->queue_capacity * sizeof(Task));}// 添加任務pool->task_queue[pool->queue_size].task = task;pool->task_queue[pool->queue_size].arg = arg;pool->queue_size++;pthread_cond_signal(&pool->task_cond);pthread_mutex_unlock(&pool->lock);
}void thread_pool_shutdown(ThreadPool *pool) {pthread_mutex_lock(&pool->lock);pool->shutdown = 1;pthread_cond_broadcast(&pool->task_cond);pthread_mutex_unlock(&pool->lock);for(int i = 0; i < THREAD_POOL_SIZE; i++) {pthread_join(pool->threads[i], NULL);}free(pool->task_queue);pthread_mutex_destroy(&pool->lock);pthread_cond_destroy(&pool->task_cond);
}

九、性能調優建議

  1. 線程數量優化

    • CPU密集型:線程數 ≈ CPU核心數
    • I/O密集型:線程數 ≈ (等待時間/計算時間 + 1) × CPU核心數
    • 使用 sysconf(_SC_NPROCESSORS_ONLN) 獲取CPU核心數
  2. 鎖競爭優化

    • 減小臨界區范圍
    • 使用讀寫鎖替代互斥鎖
    • 嘗試無鎖數據結構(atomic操作)
    • 使用線程本地存儲減少共享
  3. 內存優化

    • 設置合理的線程棧大小
    • 避免false sharing(緩存行對齊)
    • 使用內存池減少動態分配

十、跨平臺注意事項

  1. Windows 兼容性:

    • 使用 pthreads-win32 或 Windows Thread API
    • 關鍵類型對應:
      • pthread_t ? HANDLE
      • pthread_mutex_t ? CRITICAL_SECTION
  2. C++11 線程庫:

    • 標準替代方案:std::thread, std::mutex
    • 優點:跨平臺、類型安全
    • 缺點:功能不如 pthread 豐富

總結

pthread 庫提供了強大靈活的多線程編程能力,核心要點:

  1. 理解線程生命周期管理(create/join/detach)
  2. 掌握同步機制(mutex/condvar/rwlock)
  3. 合理使用線程特定數據
  4. 遵循線程安全設計原則
  5. 重視資源管理和錯誤處理

通過合理使用 pthread,可以構建高性能、高并發的應用程序,充分利用多核處理器的計算能力。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/86776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/86776.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/86776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

cocos creator 3.8 - 精品源碼 - 六邊形消消樂(六邊形疊疊樂、六邊形堆疊戰士)

cocos creator 3.8 - 精品源碼 - 六邊形消消樂 游戲介紹功能介紹免費體驗下載開發環境游戲截圖免費體驗 游戲介紹 六邊形堆疊戰士(六邊形消消消)是一款脫胎于2048、1010&#xff0c;基于俄羅斯方塊的魔性方塊達人小游戲&#xff0c;可以多方向多造型消除哦&#xff01; 功能介…

3ds Max高效運行配置核心要素

要保障3ds Max流暢運行&#xff0c;需圍繞計算性能、圖形處理、數據吞吐三大維度構建硬件體系。不同工作環節對硬件需求存在顯著差異&#xff1a; 一、核心組件配置原則 CPU&#xff1a;線程與頻率雙優化 建模/視口操作&#xff1a;依賴高主頻&#xff08;建議≥4.0GHz&#…

實變與泛函題解-心得筆記【16】

文章目錄 集合參考文獻 集合 參考文獻 《實變函數論與泛函分析》

道路交通標志檢測數據集-智能地圖與導航 交通監控與執法 智慧城市交通管理-2,000 張圖像

道路交通標志檢測數據集 &#x1f4e6; 已發布目標檢測數據集合集&#xff08;持續更新&#xff09;&#x1f6a7; 道路交通標志檢測數據集介紹&#x1f4cc; 數據集概覽包含類別 &#x1f3af; 應用場景&#x1f5bc; 數據樣本展示 YOLOv8 訓練實戰&#x1f4e6; 1. 環境配置 …

一、jenkins介紹和gitlab部署

一、jenkins介紹 jenkins和持續集成的關系 Jenkins 是實現持續集成&#xff08;CI&#xff09;最流行的自動化工具&#xff0c;它負責自動構建、測試和部署代碼&#xff0c;確保團隊能頻繁且可靠地集成代碼變更。 持續集成和敏捷開發的關系 敏捷開發是一種"快速迭代、…

k3s or kubesphere helm安裝報錯dial tcp 127.0.0.1:8080: connect: connection refused

在安裝kubesphere時報錯 Error: Kubernetes cluster unreachable: Get "http://localhost:8080/version": dial tcp 127.0.0.1:8080: connect: connection refused helm.go:92: 2025-06-27 15:14:43.30908177 0000 UTC m0.033127135 [debug] Get "http://localh…

使用datafusion和tpchgen-rs進行完整的TPCH 22個查詢的基準測試

1.從源碼編譯bench二進制文件。 下載datafusion源碼, 解壓到目錄&#xff0c;比如/par/dafu&#xff0c; cd /par/dafu/benchmarks export CARGO_INCREMENTAL1 export PATH/par:/par/mold240/bin:$PATH因為mold默認使用并行編譯&#xff0c;而這些二進制文件很大&#xff0c;如…

【軟考高項論文】論信息系統項目的干系人管理

摘要 在信息系統項目管理里&#xff0c;干系人管理極為關鍵&#xff0c;它不僅決定項目成敗&#xff0c;還對項目進度、質量和成本有著直接影響。本文結合作者2024年6月參與管理的信息系統項目&#xff0c;詳細闡述了項目干系人管理的過程&#xff0c;分析了干系人管理與溝通管…

PB應用變為Rust語言方案

從PB(PowerBuilder)遷移到現代開發軟件 PowerBuilder(PB)作為早期的快速應用開發工具,曾廣泛應用于企業級數據庫應用開發。隨著技術發展,PB逐漸面臨以下挑戰,促使企業轉向現代開發工具: 技術陳舊與維護困難 PB的架構基于較老的客戶端-服務器模式,難以適應云原生、微…

【大模型】Query 改寫常見Prompt 模板

下面對常見的幾種“Query 改寫”Prompt 模板進行中英文對照&#xff0c;并在注釋中給出中文說明&#xff0c;幫助中國用戶快速理解與使用。 根據調研&#xff0c;企業級 Query 改寫模塊需要覆蓋多種常見場景&#xff0c;包括拼寫糾錯、中英混合、省略上下文、多義詞擴展、專業術…

西門子S7-200 SMART PLC:小型自動化領域的高效之選

在工業自動化領域&#xff0c;小型PLC作為設備控制的核心組件&#xff0c;其性能、靈活性和性價比始終是用戶關注的重點。西門子推出的S7-200 SMART可編程控制器&#xff0c;憑借對中國市場需求的精準把握&#xff0c;成為了小型自動化解決方案的標桿產品。本文將從產品亮點、技…

使用iperf3測試網絡的方法

深入掌握網絡性能測試&#xff1a;iperf3全指南 在網絡優化、故障排查和帶寬驗證中&#xff0c;iperf 是工程師必備的利器。這款開源工具通過模擬數據流&#xff0c;精準測量??帶寬、抖動、丟包率??等核心指標。本文將結合實戰經驗&#xff0c;詳解iperf的安裝、參數配置和…

Level2.11繼承

一、繼承 #動物# #老虎、獅子、大象 #動物有共性 ##定義一個動物&#xff1a;1.有4條腿&#xff1b;2.陸地上跑&#xff1b;3.需要進食&#xff08;屬性能力&#xff09; ##貓&#xff1a;同上&#xff08;繼承了動物的屬性和能力&#xff09; ##老鼠&#xff1a;同上#Python…

Class3Softmax回歸

Class3Softmax回歸 回歸VS分類 回歸是估計一個連續值 分類是預測一個離散類別 回歸分類單連續值輸出通常為多個輸出自然區間R輸出i是預測為第i類的置信度跟真實值的區別作為損失 生活中的分類問題 1.垃圾分類 類別&#xff1a; 可回收物 濕垃圾&#xff08;廚余垃圾&#xff0…

day042-負載均衡與web集群搭建

文章目錄 0. 老男孩思想-面試官問&#xff1a;你對加班的看法?1. 負載均衡2. 搭建負載均衡的WordPress集群2.1 負載均衡服務器2.2 配置web服務器2.3 測試 踩坑記錄1. /var/cache/nginx權限問題 0. 老男孩思想-面試官問&#xff1a;你對加班的看法? 互聯網公司沒有不加班的&a…

40歲技術人用AI尋找突破路線

年近40&#xff0c;坐標重慶&#xff0c;從事醫療器械行業多年&#xff0c;遇到發展瓶頸。剛好遇到AI技術浪潮。最近一年在不斷嘗試把AI應用于工作生活的方方面面。 總結一下我是如何利用AI來做職業規劃的&#xff1a; 整理好自己的簡歷&#xff0c;越詳細越好。這個可以利用…

kde截圖工具報錯

An error occurred while taking a screenshot. KWin screenshot request failed: The process is not authorized to take a screenshot Potentially relevant information: - Method: CaptureScreen - Method specific arguments: "eDP-2"好的&#xff0c;感謝您提…

有理函數積分——分式分解時設分解式的規則

目錄 一、設前處理 1. 假式化真式 2. 分母因式分解 3. 判斷可約不可約 二、一次分母 1. 多項一次分母? 2. 單項一次重復分母? 三、二次分母(當然是分母不可約的&#xff0c;如果可約就因式分解然后對應一次分母) 1. 多項二次分母? 2. 單項二次重復分母? 四、混…

從 AJAX 到 axios:前端與服務器通信實戰指南

直到現在我們小寧已經更新了44作品了&#xff0c;其中和大家介紹了Python入門基礎、Fast API框架、SQLite數據庫&#xff0c;以及前端的知識都已經學習完了&#xff0c;總的來說現在前端、后端、數據庫已經都學習了&#xff0c;那大家是否有這樣的疑問&#xff0c;前端后端到底…

Pycatia二次開發基礎代碼解析:面屬性控制、視圖定向與特征統計的工業級實現

本文將以專業視角深入解析CATIA二次開發中的三個核心類方法&#xff0c;通過詳細分析代碼實現揭示其在工業設計中的實際應用價值。全文將嚴格圍繞提供的代碼展開&#xff0c;不做任何修改或補充。 一、面屬性控制&#xff1a;精確可視化表達技術 方法功能解析 color_and_laye…