執行緒池見解

不懂小白在线记录發表於2024-06-12

執行緒池

執行緒池是一種用於管理和最佳化多執行緒應用程式效能的設計模式。它預先建立一組執行緒,並將任務分配給這些執行緒執行,從而減少了建立和銷燬執行緒的開銷,提高了系統的效率和響應速度。

目錄
  • 執行緒池
      • 執行緒池的基本概念
      • 執行緒池的優點
      • 執行緒池的實現原理
      • 執行緒示意圖
      • 圖片說明
      • 工作流程
      • 優點
      • 執行緒池的基本操作
      • 工作執行緒函式
      • 執行緒池建立函式
      • 新增任務函式
      • 銷燬執行緒池函式
      • 示例任務函式
      • 主函式
      • 程式碼詳細說明

執行緒池的基本概念

  1. 執行緒池:一個包含多個執行緒的集合,這些執行緒可以被重複使用來執行多個任務。
  2. 任務佇列:一個儲存等待執行任務的佇列。當有新的任務到來時,它們會被新增到這個佇列中。
  3. 工作執行緒:執行緒池中的執行緒,這些執行緒會不斷從任務佇列中取出任務並執行。
  4. 執行緒池管理器:負責管理執行緒池的生命週期,包括執行緒的建立、銷燬和任務的分配。

執行緒池的優點

  1. 減少執行緒建立和銷燬的開銷:執行緒的建立和銷燬是昂貴的操作。執行緒池透過重用執行緒減少了這些開銷。
  2. 提高響應速度:當任務到來時,不需要等待執行緒建立,可以立即使用執行緒池中的空閒執行緒執行任務。
  3. 控制併發量:可以透過限制執行緒池中的最大執行緒數來控制系統的併發量,防止資源耗盡。
  4. 統一管理:執行緒池提供了一個統一的管理介面,可以更方便地監控和調優執行緒的使用。

執行緒池的實現原理

執行緒池的實現通常包括以下幾個部分:

  1. 執行緒池初始化:建立一個固定數量的執行緒並將它們放入執行緒池中。

  2. 任務提交:提供一個介面,將任務新增到任務佇列中。

  3. 任務排程:執行緒池中的工作執行緒不斷從任務佇列中取出任務並執行。

  4. 執行緒管理:根據系統負載動態調整執行緒池的大小(可選)。

執行緒示意圖

以下是一個示意圖,展示了執行緒池的基本結構和工作流程:

+-------------------------+
|      Thread Pool        |
|                         |
|  +-------------------+  |
|  |   Worker Thread   |  |
|  |    (Thread 1)     |  |
|  +-------------------+  |
|                         |
|  +-------------------+  |
|  |   Worker Thread   |  |
|  |    (Thread 2)     |  |
|  +-------------------+  |
|                         |
|  +-------------------+  |
|  |   Worker Thread   |  |
|  |    (Thread 3)     |  |
|  +-------------------+  |
|                         |
|  +-------------------+  |
|  |   Worker Thread   |  |
|  |    (Thread 4)     |  |
|  +-------------------+  |
|                         |
+-------------------------+

+-------------------------+
|      Task Queue         |
|                         |
|  +-------------------+  |
|  |       Task 1      |  |
|  +-------------------+  |
|                         |
|  +-------------------+  |
|  |       Task 2      |  |
|  +-------------------+  |
|                         |
|  +-------------------+  |
|  |       Task 3      |  |
|  +-------------------+  |
|                         |
|  +-------------------+  |
|  |       Task 4      |  |
|  +-------------------+  |
|                         |
+-------------------------+

圖片說明

  1. 執行緒池 (Thread Pool)
    • 包含多個工作執行緒(Worker Thread),如圖中的 Thread 1 到 Thread 4。
    • 這些工作執行緒在建立後會一直存在,並等待任務的到來。
  2. 任務佇列 (Task Queue)
    • 儲存待執行的任務,如圖中的 Task 1 到 Task 4。
    • 當有新的任務到來時,它們會被新增到這個佇列中。

工作流程

  1. 任務提交
    • 新的任務被提交到任務佇列中。
  2. 任務分配
    • 執行緒池中的工作執行緒不斷地從任務佇列中取出任務並執行。
    • 每個工作執行緒在完成當前任務後,會繼續從佇列中取出下一個任務,直到任務佇列為空。
  3. 任務執行
    • 工作執行緒執行任務函式,並處理任務引數。
  4. 執行緒重用
    • 工作執行緒在完成任務後不會被銷燬,而是繼續等待新的任務到來,從而實現執行緒的重用。

優點

  • 減少執行緒建立和銷燬的開銷:透過重用執行緒,減少了頻繁建立和銷燬執行緒的開銷。
  • 提高響應速度:任務可以立即由空閒執行緒執行,而不需要等待新執行緒的建立。
  • 控制併發量:透過限制執行緒池中的最大執行緒數,控制系統的併發量,防止資源耗盡。

執行緒池的基本操作

執行緒池相關標頭檔案,宏定義以及結構體,包含執行緒池的所有狀態資訊,包括執行緒陣列、任務佇列、鎖和條件變數

 /****************************************************************
  *
  *	name	 :	threadpool
  *	function :  建立一個執行緒池,其中有四個執行緒,將任務分配給執行緒,完成任務可以回收執行緒,也可以新增執行緒,也可以銷燬執行緒
  *	argument :  
  *	retval	 :  None
  *	author	 :  yq_dyx@163.com
  *	date	 :  2024/06/11
  * note	 :  None
  * 	
 ****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#define MAX_THREADS 4  // 執行緒池中的最大執行緒數
#define MAX_QUEUE 10   // 任務佇列的最大大小

// 定義任務結構體
typedef struct {
    void (*function)(void*);  // 任務函式指標
    void* argument;           // 任務函式引數
} task_t;

// 定義執行緒池結構體
typedef struct {
    pthread_mutex_t lock;          // 互斥鎖
    pthread_cond_t notify;         // 條件變數
    pthread_t threads[MAX_THREADS]; // 執行緒陣列
    task_t queue[MAX_QUEUE];       // 任務佇列
    int queue_size;                // 任務佇列大小
    int head;                      // 佇列頭索引
    int tail;                      // 佇列尾索引
    int count;                     // 佇列中任務計數
    int shutdown;                  // 執行緒池關閉標誌
} threadpool_t;

工作執行緒函式

執行緒池中每個執行緒執行的函式,從任務佇列中取出任務並執行,如果執行緒池關閉,執行緒進入等待狀態,如果執行緒池關閉,執行緒退出.

void* thread_do_work(void* arg) {
    threadpool_t* pool = (threadpool_t*)arg;  // 獲取執行緒池指標
    task_t task;

    while (1) {
        pthread_mutex_lock(&(pool->lock));  // 加鎖

        // 等待任務佇列中有任務或執行緒池關閉
        while ((pool->count == 0) && (!pool->shutdown)) {
            pthread_cond_wait(&(pool->notify), &(pool->lock));
        }

        // 如果執行緒池關閉,退出執行緒
        if (pool->shutdown) {
            pthread_mutex_unlock(&(pool->lock));
            pthread_exit(NULL);
        }

        // 從任務佇列中取出任務
        task.function = pool->queue[pool->head].function;
        task.argument = pool->queue[pool->head].argument;
        pool->head = (pool->head + 1) % MAX_QUEUE;
        pool->count -= 1;

        pthread_mutex_unlock(&(pool->lock));  // 解鎖

        // 執行任務
        (*(task.function))(task.argument);
    }

    pthread_exit(NULL);
    return NULL;
}

執行緒池建立函式

  • 初始化執行緒池結構體。
  • 初始化互斥鎖和條件變數。
  • 建立工作執行緒
// 建立執行緒池
threadpool_t* threadpool_create() {
    threadpool_t* pool = (threadpool_t*)malloc(sizeof(threadpool_t));
    if (pool == NULL) {
        return NULL;  // 分配記憶體失敗
    }

    pool->queue_size = MAX_QUEUE;
    pool->head = pool->tail = pool->count = 0;
    pool->shutdown = 0;

    // 初始化互斥鎖和條件變數
    pthread_mutex_init(&(pool->lock), NULL);
    pthread_cond_init(&(pool->notify), NULL);

    // 建立工作執行緒
    for (int i = 0; i < MAX_THREADS; i++) {
        pthread_create(&(pool->threads[i]), NULL, thread_do_work, (void*)pool);
    }

    return pool;
}

新增任務函式

  • 向任務佇列中新增任務。
  • 如果任務佇列已滿,返回錯誤。
  • 通知工作執行緒有新任務。
// 向執行緒池新增任務
int threadpool_add(threadpool_t* pool, void (*function)(void*), void* argument) {
    pthread_mutex_lock(&(pool->lock));  // 加鎖

    int next = (pool->tail + 1) % pool->queue_size;

    // 如果任務佇列已滿,返回錯誤
    if (pool->count == pool->queue_size) {
        pthread_mutex_unlock(&(pool->lock));
        return -1;  // 任務佇列已滿
    }

    // 新增任務到任務佇列
    pool->queue[pool->tail].function = function;
    pool->queue[pool->tail].argument = argument;
    pool->tail = next;
    pool->count += 1;

    // 通知工作執行緒有新任務
    pthread_cond_signal(&(pool->notify));
    pthread_mutex_unlock(&(pool->lock));  // 解鎖

    return 0;
}

銷燬執行緒池函式

  • 設定關閉標誌,通知所有工作執行緒。
  • 等待所有工作執行緒結束。
  • 銷燬互斥鎖和條件變數,釋放執行緒池記憶體。
// 銷燬執行緒池
void threadpool_destroy(threadpool_t* pool) {
    pthread_mutex_lock(&(pool->lock));  // 加鎖
    pool->shutdown = 1;  // 設定關閉標誌
    pthread_cond_broadcast(&(pool->notify));  // 通知所有工作執行緒
    pthread_mutex_unlock(&(pool->lock));  // 解鎖

    // 等待所有工作執行緒結束
    for (int i = 0; i < MAX_THREADS; i++) {
        pthread_join(pool->threads[i], NULL);
    }

    // 銷燬互斥鎖和條件變數
    pthread_mutex_destroy(&(pool->lock));
    pthread_cond_destroy(&(pool->notify));
    free(pool);  // 釋放執行緒池記憶體
}

示例任務函式

模擬任務執行,列印任務資訊並休眠1秒

// 示例任務函式
void example_task(void* arg) {
    int num = *(int*)arg;
    printf("Thread %lu is working on task %d\n", pthread_self(), num);
    sleep(1);  // 模擬任務執行時間
}

主函式

  • 建立執行緒池。
  • 向執行緒池新增任務。
  • 等待所有任務完成。
  • 銷燬執行緒池。
int main() {
    // 建立執行緒池
    threadpool_t* pool = threadpool_create();
    if (pool == NULL) {
        fprintf(stderr, "Failed to create thread pool\n");
        return 1;
    }

    // 向執行緒池新增任務
    int tasks[20];
    for (int i = 0; i < 20; i++) {
        tasks[i] = i;
        threadpool_add(pool, example_task, (void*)&tasks[i]);
    }

    sleep(5);  // 等待所有任務完成
    threadpool_destroy(pool);  // 銷燬執行緒池

    return 0;
}

程式碼詳細說明

  1. 任務結構體 task_t
    • function:指向任務函式的指標。
    • argument:任務函式的引數。
  2. 執行緒池結構體 threadpool_t
    • lock:互斥鎖,用於保護共享資源。
    • notify:條件變數,用於通知工作執行緒有新任務到來。
    • threads:執行緒陣列,儲存執行緒池中的執行緒。
    • queue:任務佇列,儲存待執行的任務。
    • queue_size:任務佇列的大小。
    • head:任務佇列的頭索引。
    • tail:任務佇列的尾索引。
    • count:任務佇列中的任務計數。
    • shutdown:執行緒池關閉標誌。
  3. 工作執行緒函式 thread_do_work
    • 從任務佇列中取出任務並執行。
    • 如果任務佇列為空且執行緒池未關閉,執行緒進入等待狀態。
    • 如果執行緒池關閉,執行緒退出。
  4. 執行緒池建立函式 threadpool_create
    • 初始化執行緒池結構體。
    • 初始化互斥鎖和條件變數。
    • 建立工作執行緒。
  5. 新增任務函式 threadpool_add
    • 向任務佇列中新增任務。
    • 如果任務佇列已滿,返回錯誤。
    • 通知工作執行緒有新任務。
  6. 銷燬執行緒池函式 threadpool_destroy
    • 設定關閉標誌,通知所有工作執行緒。
    • 等待所有工作執行緒結束。
    • 銷燬互斥鎖和條件變數,釋放執行緒池記憶體。
  7. 示例任務函式 example_task
    • 模擬任務執行,列印任務資訊並休眠1秒。
  8. 主函式 main
    • 建立執行緒池。
    • 向執行緒池新增任務。
    • 等待所有任務完成。
    • 銷燬執行緒池。

相關文章