色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

C語言線程池的實現方案

汽車電子技術 ? 來源:老吳的嵌入式之旅 ? 作者:吳偉東Jack ? 2023-01-29 16:43 ? 次閱讀

一、簡介

https://github.com/Pithikos/C-Thread-Pool

這是一個簡單小巧的C語言線程池實現,在 Github 上有 1.1K 的 star,很適合用來學習 Linux 的多線程編程

另外,里面還涉及到了信號、隊列、同步等知識點,代碼讀起來還是挺過癮的。

特點:

  • 符合 ANCI C and POSIX;
  • 支持暫停/恢復/等待功能;
  • 簡潔的 API;
  • 經過嚴格的測試,附帶了豐富的測試用例;

二、使用

快速上手

example.c:

#include "thpool.h"

void task(void *arg){
 printf("Thread #%u working on %d
", (int)pthread_self(), (int) arg);
}

int main(){
 
 puts("Making threadpool with 4 threads");
 threadpool thpool = thpool_init(4);

 puts("Adding 10 tasks to threadpool");
 int i;
 for (i=0; i<8; i++){
  thpool_add_work(thpool, task, (void*)(uintptr_t)i);
 };

 thpool_wait(thpool);
 puts("Killing threadpool");
 thpool_destroy(thpool);
 
 return 0;
}

運行效果:

$ gcc example.c thpool.c -D THPOOL_DEBUG -pthread -o example

$ ./example
Making threadpool with 4 threads
THPOOL_DEBUG: Created thread 0 in pool 
THPOOL_DEBUG: Created thread 1 in pool 
THPOOL_DEBUG: Created thread 2 in pool 
THPOOL_DEBUG: Created thread 3 in pool 
Adding 10 tasks to threadpool
Thread #1509455616 working on 0
Thread #1509455616 working on 4
Thread #1509455616 working on 5
Thread #1492670208 working on 2
Thread #1492670208 working on 7
Thread #1509455616 working on 6
Thread #1501062912 working on 1
Thread #1517848320 working on 3
Killing threadpool

代碼分析:

  • threadpool thpool = thpool_init(4) 創建了一個含有 4 個線程的線程池;
  • 然后調用 thpool_add_work(thpool, ...) 往線程池里放入了 8 個任務;
  • 從結果來看:
    • 線程5616 搶到了任務 0 / 4 / 5 / 6;
    • 線程0208 搶到了任務 2 / 7;
    • 線程2919 搶到了任務 1;
    • 線程8320 搶到了任務 3;

API 簡介

示例 作用
thpool_init(4) 創建一個含有 4 個線程的線程池。
* thpool_add_work(thpool, (void)function_p, (void )arg_p)* ** 添加任務, function_p 是任務要執行的函數,arg_p 是 function_p 的參數
thpool_wait(thpool) 等待所有任務完成。
thpool_destroy(thpool) 銷毀線程池,如果還有任務在執行,則會先等待其完成。
thpool_pause(thpool) 讓所有的線程都停止工作,進入睡眠狀態。
thpool_resume(thpool) 讓所有的線程都恢復工作。
thpool_num_threads_working(thpool) 返回當前正在工作的線程數。

三、內部實現

整體把握

核心代碼就是 2 個文件:thpool.c 和 thpool.h。

分解 thpool.c

7 個公共函數:

struct thpool_* thpool_init(int num_threads) 
int thpool_add_work(thpool_* thpool_p, void (*function_p)(void*), void* arg_p) 
void thpool_wait(thpool_* thpool_p) 
void thpool_destroy(thpool_* thpool_p) 
void thpool_pause(thpool_* thpool_p) 
void thpool_resume(thpool_* thpool_p) 
int thpool_num_threads_working(thpool_* thpool_p)

正好就是前面說過的 7 個 API,稍后重點分析。

5 個自定義的數據結構:

// 描述一個信號量
typedef struct bsem {...} bsem;

// 描述一個任務
typedef struct job {...} job;

// 描述一個任務隊列
typedef struct jobqueue {...} jobqueue;

// 描述一個線程
typedef struct thread {...} thread;

// 描述一個線程池
typedef struct thpool_ {...} thpool_;

14 個私有函數:

// 構造 struct thread,并調用 pthread_create() 創建線程
static int thread_init (thpool_* thpool_p, struct thread** thread_p, int id) 

// 當線程被暫停時會在這里休眠
static void thread_hold(int sig_id) 

// 線程在此函數中執行任務
static void* thread_do(struct thread* thread_p) 

// 銷毀 struct thread
static void thread_destroy (thread* thread_p) 

// 任務隊列相關的操作集合
static int jobqueue_init(jobqueue* jobqueue_p) 
static void jobqueue_clear(jobqueue* jobqueue_p) 
static void jobqueue_push(jobqueue* jobqueue_p, struct job* newjob) 
static struct job* jobqueue_pull(jobqueue* jobqueue_p) 
static void jobqueue_destroy(jobqueue* jobqueue_p) 

// 信號量相關的操作集合
static void bsem_init(bsem *bsem_p, int value) 
static void bsem_reset(bsem *bsem_p) 
static void bsem_post(bsem *bsem_p) 
static void bsem_post_all(bsem *bsem_p) 
static void bsem_wait(bsem* bsem_p)

核心 API 的實現

1. thpool_init()

該函數用于創建一個線程池,先明確線程池的定義:

typedef struct thpool_{
 thread**   threads;                  /* pointer to threads        */
 volatile int num_threads_alive;      /* threads currently alive   */
 volatile int num_threads_working;    /* threads currently working */
 pthread_mutex_t  thcount_lock;       /* used for thread count etc */
 pthread_cond_t  threads_all_idle;    /* signal to thpool_wait     */
 jobqueue  jobqueue;                  /* job queue                 */
} thpool_;

thpool_init() 的實現思路:

  1. 分配 struct thpool_:
    • malloc(sizeof(struct thpool_))
  2. 初始化 struct thpool_;
    • malloc(num_threads * sizeof(struct thread *))
    • thread_init(thpool_p, &thpool_p->threads[n], n);
    • jobqueue_init(&thpool_p->jobqueue)
    • 初始化 jobqueue:
    • 創建用戶指定數目的線程,用一個二級指針來指向這一組線程;
  3. 返回 struct thpool_ *;

2. thpool_add_work()

該函數用于往線程池里添加一個任務,先明確任務的定義:

typedef struct job{
 struct job*  prev; /* pointer to previous job */
 void   (*function)(void* arg);  /* function pointer */
 void*  arg;  /* function's argument */
} job;

程序里是用隊列來管理任務的,這里的 job 首先是一個隊列節點,攜帶的數據是 function + arg。

thpool_add_work 的實現思路:

  1. 分配 struct job:
    • malloc(sizeof(struct job))
  2. 初始化 struct job;
    • newjob->function=function_p;
    • newjob->arg=arg_p;
  3. 添加到隊列中:
    • jobqueue_push(&thpool_p->jobqueue, newjob);

3. thpool_pause() 和 thpool_resume()

thpool_pause() 用于暫停所有的線程,通過信號機制來實現:

void thpool_pause(thpool_* thpool_p) {
 int n;
 for (n=0; n < thpool_p->num_threads_alive; n++){
  pthread_kill(thpool_p->threads[n]->pthread, SIGUSR1);
 }
}

給所有工作線程發送 SIGUSR1,該信號的處理行為就是讓線程休眠:

static void thread_hold(int sig_id) {
    (void)sig_id;
 threads_on_hold = 1;
 while (threads_on_hold){
  sleep(1);
 }
}

只需要 thpool_resume() 中,將 threads_on_hold = 0,就可以讓線程返回到原來被中止時的工作狀態。

4. thpool_wait()

wait 的實現比較簡單,只要還有任務或者還有線程處于工作狀態,就執行 pthread 的 wait 操作:

while (thpool_p->jobqueue.len || thpool_p->num_threads_working) {
  pthread_cond_wait(&thpool_p->threads_all_idle, &thpool_p->thcount_lock);
 }

到此,我感覺已經沒有太多難點了,感興趣的小伙伴們可以自行查閱源碼。

四、測試用例

優秀的開源項目通常會附帶豐富的測試用例,此項目也不例外:

  • memleaks.sh:測試是否發生內存泄露;
  • threadpool.sh: 測試線程池是否能正確地執行任務;
  • pause_resume.sh:測試 pause 和 resume 是否正常;
  • wait.sh:測試 wait 功能是否正常;
  • heap_stack_garbage:測試堆棧內有垃圾數據時的情況;
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11292

    瀏覽量

    209326
  • C語言
    +關注

    關注

    180

    文章

    7604

    瀏覽量

    136685
  • 線程池
    +關注

    關注

    0

    文章

    57

    瀏覽量

    6844
  • 線程
    +關注

    關注

    0

    文章

    504

    瀏覽量

    19675
  • GitHub
    +關注

    關注

    3

    文章

    468

    瀏覽量

    16428
收藏 人收藏

    評論

    相關推薦

    跨平臺的線程組件--TP組件

    問題產生 無論是Linux,RTOS,還是Android等開發,我們都會用到多線程編程;但是往往很多人在編程時,都很隨意的創建/銷毀線程的策略來實現線程編程;很明顯這是不合理的做法,
    的頭像 發表于 04-06 15:39 ?871次閱讀

    Java中的線程包括哪些

    java.util.concurrent 包來實現的,最主要的就是 ThreadPoolExecutor 類。 Executor: 代表線程的接口,有一個 execute() 方法,給一個 Runnable 類型對象
    的頭像 發表于 10-11 15:33 ?809次閱讀
    Java中的<b class='flag-5'>線程</b><b class='flag-5'>池</b>包括哪些

    線程是如何實現

    線程的概念是什么?線程是如何實現的?
    發表于 02-28 06:20

    基于Nacos的簡單動態化線程實現

    本文以Nacos作為服務配置中心,以修改線程核心線程數、最大線程數為例,實現一個簡單的動態化線程
    發表于 01-06 14:14 ?862次閱讀

    線程線程

    線程通常用于服務器應用程序。 每個傳入請求都將分配給線程池中的一個線程,因此可以異步處理請求,而不會占用主線程,也不會延遲后續請求的處理
    的頭像 發表于 02-28 09:53 ?786次閱讀
    多<b class='flag-5'>線程</b>之<b class='flag-5'>線程</b><b class='flag-5'>池</b>

    如何用C++實現一個線程呢?

    C++線程是一種多線程管理模型,把線程分成任務執行和線程調度兩部分。
    發表于 06-08 14:53 ?1765次閱讀
    如何用<b class='flag-5'>C</b>++<b class='flag-5'>實現</b>一個<b class='flag-5'>線程</b><b class='flag-5'>池</b>呢?

    細數線程的10個坑

    JDK開發者提供了線程實現類,我們基于Executors組件,就可以快速創建一個線程
    的頭像 發表于 06-16 10:11 ?722次閱讀
    細數<b class='flag-5'>線程</b><b class='flag-5'>池</b>的10個坑

    線程線程怎么釋放

    線程分組看,pool名開頭線程占616條,而且waiting狀態也是616條,這個點就非常可疑了,我斷定就是這個pool開頭線程導致的問題。我們先排查為何這個
    發表于 07-31 10:49 ?2274次閱讀
    <b class='flag-5'>線程</b><b class='flag-5'>池</b>的<b class='flag-5'>線程</b>怎么釋放

    Spring 的線程應用

    我們在日常開發中,經常跟多線程打交道,Spring 為我們提供了一個線程方便我們開發,它就是 ThreadPoolTaskExecutor ,接下來我們就來聊聊 Spring 的線程
    的頭像 發表于 10-13 10:47 ?620次閱讀
    Spring 的<b class='flag-5'>線程</b><b class='flag-5'>池</b>應用

    線程基本概念與原理

    一、線程基本概念與原理 1.1 線程概念及優勢 C++線程
    的頭像 發表于 11-10 10:24 ?528次閱讀

    線程的基本概念

    線程的基本概念 不管線程是什么東西!但是我們必須知道線程被搞出來的目的就是:提高程序執行效
    的頭像 發表于 11-10 16:37 ?520次閱讀
    <b class='flag-5'>線程</b><b class='flag-5'>池</b>的基本概念

    如何用C語言實現線程

    線程是一種多線程處理形式,大多用于高并發服務器上,它能合理有效的利用高并發服務器上的線程資源;線程與進程用于處理各項分支子功能,我們通常的
    的頭像 發表于 11-13 10:41 ?1039次閱讀
    如何用<b class='flag-5'>C</b><b class='flag-5'>語言實現</b><b class='flag-5'>線程</b><b class='flag-5'>池</b>

    基于C++11的線程實現

    C++11 加入了線程庫,從此告別了標準庫不支持并發的歷史。然而 c++ 對于多線程的支持還是比較低級,稍微高級一點的用法都需要自己去實現
    的頭像 發表于 11-13 15:29 ?759次閱讀

    線程的創建方式有幾種

    線程是一種用于管理和調度線程的技術,能夠有效地提高系統的性能和資源利用率。它通過預先創建一組線程并維護一個工作隊列,將任務提交給線程
    的頭像 發表于 12-04 16:52 ?854次閱讀

    什么是動態線程?動態線程的簡單實現思路

    因此,動態可監控線程一種針對以上痛點開發的線程管理工具。主要可實現功能有:提供對 Spring 應用內
    的頭像 發表于 02-28 10:42 ?639次閱讀
    主站蜘蛛池模板: 亚洲视频 在线观看| 蜜芽一二三区| 国产最新地址| 国产高清视频青青青在线| 成人动漫百度影音| 成人小视频免费在线观看| 村上里沙快播| 国产99在线视频| 国产精品永久免费视频| 国产精品人妻系列21P| 国产精品久久久久久久久久久| 动漫美女脱小内内露尿口| 高清国产激情视频在线观看| 国产成人精品男人的天堂网站 | 影音先锋男人资源813.| 一二三四在线视频社区| 91热久久免费精品99| 99久久精品免费精品国产| 超碰视频97av| 国产欧美一区二区精品性色tv| 换脸国产AV一区二区三区| 久久9精品区-无套内射无码| 免费完整版观看| 泰国淫乐园实录| 伊人久久精品午夜| 成年女人免费影院播放| 国产人妻午夜无码AV天堂| 啦啦啦影院视频在线看高清...| 欧美亚洲日韩自拍高清中文| 午夜国产精品影院在线观看| 最新国产三级在线不卡视频| 大地影院免费观看视频| 娇妻中日久久持久久| 日本护士在线观看| 一道本无吗d d在线播放| 不卡人妻无码AV中文系列APP| 精品亚洲麻豆1区2区3区| 全免费a级毛片免费看| 在线成年av动漫电影| 国产精品一区二区AV白丝在线| 欧美成人无码视频午夜福利|