C語言線程池的常見實(shí)現(xiàn)方式詳解
在 C 語言中,線程池通常通過 pthread
庫來實(shí)現(xiàn)。以下是一個(gè)詳細(xì)的說明,介紹了 C 語言線程池的常見實(shí)現(xiàn)方式,包括核心概念、實(shí)現(xiàn)步驟和具體的代碼示例。
1. 線程池的基本結(jié)構(gòu)
線程池的核心概念是有一個(gè)固定數(shù)量的線程等待執(zhí)行任務(wù)。任務(wù)通常通過任務(wù)隊(duì)列傳遞,線程從隊(duì)列中取出任務(wù)并執(zhí)行。線程池的主要目標(biāo)是提高資源利用率,避免頻繁地創(chuàng)建和銷毀線程。
線程池的主要組件:
- 任務(wù)結(jié)構(gòu):保存任務(wù)信息,比如任務(wù)的函數(shù)指針和參數(shù)。
- 任務(wù)隊(duì)列:用于存放待處理的任務(wù)。當(dāng)所有工作線程都在忙時(shí),新提交的任務(wù)會(huì)被放到隊(duì)列中,直到線程空閑出來。
- 線程池控制:管理線程池的線程,調(diào)度任務(wù)的分發(fā),維護(hù)任務(wù)隊(duì)列。
2. 線程池的實(shí)現(xiàn)步驟
以下是實(shí)現(xiàn)一個(gè)簡(jiǎn)單線程池的基本步驟:
初始化線程池:
創(chuàng)建一定數(shù)量的線程,并使它們處于等待狀態(tài)。
創(chuàng)建一個(gè)任務(wù)隊(duì)列,用來存儲(chǔ)待執(zhí)行的任務(wù)。
任務(wù)提交:
用戶提交任務(wù)到線程池,線程池會(huì)把任務(wù)放入任務(wù)隊(duì)列中,等待工作線程去執(zhí)行。
工作線程:
工作線程從任務(wù)隊(duì)列中取出任務(wù)并執(zhí)行。
如果沒有任務(wù),線程會(huì)阻塞,直到有任務(wù)提交到任務(wù)隊(duì)列。
關(guān)閉線程池:
關(guān)閉線程池時(shí),需要確保所有任務(wù)完成后再銷毀線程池,并且釋放所有資源。
3. 線程池的核心數(shù)據(jù)結(jié)構(gòu)
任務(wù)結(jié)構(gòu): 每個(gè)任務(wù)通常包括任務(wù)的執(zhí)行函數(shù)和任務(wù)的參數(shù)。
typedef struct { void (*routine)(void *arg); // 任務(wù)執(zhí)行的函數(shù) void *arg; // 傳遞給任務(wù)函數(shù)的參數(shù) } task_t;
線程池結(jié)構(gòu): 線程池需要包含任務(wù)隊(duì)列、線程數(shù)組、線程數(shù)量、鎖以及條件變量等。
typedef struct { pthread_t *threads; // 工作線程數(shù)組 task_t *task_queue; // 任務(wù)隊(duì)列 int queue_size; // 隊(duì)列大小 int head, tail; // 隊(duì)列頭尾索引 int thread_count; // 線程池中的線程數(shù) pthread_mutex_t lock; // 鎖,保護(hù)任務(wù)隊(duì)列 pthread_cond_t cond; // 條件變量,喚醒工作線程 int shutdown; // 是否關(guān)閉線程池 } thread_pool_t;
4. 線程池的詳細(xì)實(shí)現(xiàn)
下面是一個(gè)完整的線程池實(shí)現(xiàn),包括初始化、任務(wù)提交、任務(wù)執(zhí)行和銷毀。
4.1 初始化線程池
首先需要?jiǎng)?chuàng)建線程池,并初始化必要的數(shù)據(jù)結(jié)構(gòu)。
#include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> typedef struct { void (*routine)(void *arg); // 任務(wù)執(zhí)行的函數(shù) void *arg; // 傳遞給任務(wù)函數(shù)的參數(shù) } task_t; typedef struct { pthread_t *threads; // 工作線程數(shù)組 task_t *task_queue; // 任務(wù)隊(duì)列 int queue_size; // 隊(duì)列大小 int head, tail; // 隊(duì)列頭尾索引 int thread_count; // 線程池中的線程數(shù) pthread_mutex_t lock; // 鎖,保護(hù)任務(wù)隊(duì)列 pthread_cond_t cond; // 條件變量,喚醒工作線程 int shutdown; // 是否關(guān)閉線程池 } thread_pool_t; void *worker(void *arg) { thread_pool_t *pool = (thread_pool_t *)arg; while (1) { pthread_mutex_lock(&pool->lock); while (pool->head == pool->tail && !pool->shutdown) { pthread_cond_wait(&pool->cond, &pool->lock); // 等待任務(wù) } // 檢查是否關(guān)閉線程池 if (pool->shutdown) { pthread_mutex_unlock(&pool->lock); break; } task_t task = pool->task_queue[pool->head]; // 獲取任務(wù) pool->head = (pool->head + 1) % pool->queue_size; // 隊(duì)列中移除任務(wù) pthread_mutex_unlock(&pool->lock); task.routine(task.arg); // 執(zhí)行任務(wù) } pthread_exit(NULL); } void thread_pool_init(thread_pool_t *pool, int thread_count, int queue_size) { pool->threads = (pthread_t *)malloc(thread_count * sizeof(pthread_t)); pool->task_queue = (task_t *)malloc(queue_size * sizeof(task_t)); pool->queue_size = queue_size; pool->head = pool->tail = 0; pool->thread_count = thread_count; pool->shutdown = 0; pthread_mutex_init(&pool->lock, NULL); pthread_cond_init(&pool->cond, NULL); // 創(chuàng)建線程 for (int i = 0; i < thread_count; i++) { pthread_create(&pool->threads[i], NULL, worker, pool); } }
4.2 提交任務(wù)
當(dāng)用戶需要執(zhí)行某個(gè)任務(wù)時(shí),任務(wù)會(huì)被加入任務(wù)隊(duì)列,等待線程執(zhí)行。
void thread_pool_add_task(thread_pool_t *pool, void (*routine)(void *), void *arg) { pthread_mutex_lock(&pool->lock); // 檢查任務(wù)隊(duì)列是否滿 if ((pool->tail + 1) % pool->queue_size != pool->head) { pool->task_queue[pool->tail].routine = routine; pool->task_queue[pool->tail].arg = arg; pool->tail = (pool->tail + 1) % pool->queue_size; // 更新隊(duì)列尾部 pthread_cond_signal(&pool->cond); // 喚醒一個(gè)工作線程 } pthread_mutex_unlock(&pool->lock); }
4.3 關(guān)閉線程池
關(guān)閉線程池時(shí),需要等待所有線程處理完任務(wù)后才能銷毀線程池??梢酝ㄟ^設(shè)置 shutdown
標(biāo)志來通知線程池停止。
void thread_pool_destroy(thread_pool_t *pool) { pthread_mutex_lock(&pool->lock); pool->shutdown = 1; pthread_cond_broadcast(&pool->cond); // 喚醒所有線程,確保線程能夠退出 pthread_mutex_unlock(&pool->lock); // 等待所有線程退出 for (int i = 0; i < pool->thread_count; i++) { pthread_join(pool->threads[i], NULL); } free(pool->threads); free(pool->task_queue); pthread_mutex_destroy(&pool->lock); pthread_cond_destroy(&pool->cond); }
4.4 示例任務(wù)函數(shù)
用戶可以定義自己的任務(wù)函數(shù),傳遞參數(shù),并在任務(wù)函數(shù)中執(zhí)行實(shí)際的工作。
void print_hello(void *arg) { printf("Hello, %s!\n", (char *)arg); } int main() { thread_pool_t pool; thread_pool_init(&pool, 4, 10); // 創(chuàng)建一個(gè)線程池,包含4個(gè)線程和10個(gè)任務(wù)隊(duì)列 for (int i = 0; i < 5; i++) { char *name = malloc(10); sprintf(name, "Task %d", i + 1); thread_pool_add_task(&pool, print_hello, name); } sleep(1); // 等待任務(wù)執(zhí)行 thread_pool_destroy(&pool); // 銷毀線程池 return 0; }
5. 線程池的調(diào)優(yōu)和優(yōu)化
在實(shí)際應(yīng)用中,線程池的性能可以通過以下幾個(gè)方面進(jìn)行調(diào)優(yōu)和優(yōu)化:
- 最大線程數(shù)和最小線程數(shù):為了避免線程過多導(dǎo)致的資源競(jìng)爭(zhēng),可以設(shè)置最小線程數(shù)和最大線程數(shù)。
- 任務(wù)隊(duì)列長(zhǎng)度:任務(wù)隊(duì)列的長(zhǎng)度要適中。過長(zhǎng)的隊(duì)列可能導(dǎo)致任務(wù)過度堆積,過短的隊(duì)列則可能導(dǎo)致線程池?zé)o法充分利用資源。
- 動(dòng)態(tài)線程調(diào)整:根據(jù)系統(tǒng)負(fù)載動(dòng)態(tài)增加或減少線程數(shù)量,能夠提高系統(tǒng)的效率和響應(yīng)速度。
- 任務(wù)超時(shí)機(jī)制:為了防止某些任務(wù)長(zhǎng)時(shí)間占用線程,線程池可以設(shè)置任務(wù)的超時(shí)機(jī)制,當(dāng)任務(wù)超時(shí)后放棄執(zhí)行或重新調(diào)度。
總結(jié)
本文介紹了如何使用 C 語言實(shí)現(xiàn)一個(gè)基本的線程池。線程池的實(shí)現(xiàn)包括工作線程、任務(wù)隊(duì)列、任務(wù)調(diào)度、線程池的初始化、任務(wù)添加、銷毀等步驟。通過這種方式,可以在多任務(wù)、高并發(fā)的場(chǎng)景中有效地管理線程,減少線程創(chuàng)建和銷毀的開銷,提高系統(tǒng)的效率。
到此這篇關(guān)于C語言線程池的常見實(shí)現(xiàn)方式詳解的文章就介紹到這了,更多相關(guān)C語言線程池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用C++將yolov8 onnx格式轉(zhuǎn)化為tensorrt格式
這篇文章主要為大家詳細(xì)介紹了如何使用C++將yolov8 onnx格式轉(zhuǎn)化為tensorrt格式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2024-11-11虛函數(shù)被類的構(gòu)造析構(gòu)函數(shù)和成員函數(shù)調(diào)用虛函數(shù)的執(zhí)行過程
虛函數(shù)被類的構(gòu)造析構(gòu)函數(shù)和成員函數(shù)調(diào)用虛函數(shù)的執(zhí)行過程,需要的朋友可以參考下2013-02-02C++中4種強(qiáng)制類型轉(zhuǎn)換的區(qū)別總結(jié)
C++風(fēng)格的類型轉(zhuǎn)換提供了4種類型轉(zhuǎn)換操作符來應(yīng)對(duì)不同場(chǎng)合的應(yīng)用。下面這篇文章主要給大家介紹了C++中4種強(qiáng)制類型轉(zhuǎn)換的區(qū)別,有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-12-12C++中memcpy和memmove的區(qū)別總結(jié)
這篇文章主要介紹了C++中memcpy和memmove的區(qū)別總結(jié),這個(gè)問題經(jīng)常出現(xiàn)在C++的面試題目中,需要的朋友可以參考下2014-10-10C語言MFC導(dǎo)出dll回調(diào)函數(shù)方法詳解
這篇文章主要為大家介紹了C語言MFC導(dǎo)出dll回調(diào)函數(shù)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11C++定時(shí)器實(shí)現(xiàn)和時(shí)間輪介紹
這篇文章主要介紹了C++定時(shí)器實(shí)現(xiàn)和時(shí)間輪介紹,定時(shí)器可以由很多種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),比如最小堆、紅黑樹、跳表、甚至數(shù)組都可以,其本質(zhì)都是拿到最小時(shí)間的任務(wù),然后取出該任務(wù)并執(zhí)行,更多相關(guān)內(nèi)容介紹,需要的小伙伴可以參考一下2022-09-09C++11中l(wèi)ambda、std::function和std:bind詳解
大家都知道C++11中增加了許多的新特性,下面在這篇文中我們就來聊一下lambda表達(dá)式,閉包,std::function以及std::bind。文中介紹的很詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,有需要的朋友們下面來一起看看吧。2017-01-01