日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux进程池、线程池调研

發布時間:2024/3/13 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux进程池、线程池调研 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.進程池

(1)進程池是由服務器預先創建的一組子進程,這些子進程的數目在3-10個之間。進程池中的所有子進程都運行著相同的代碼,并具有相同的屬性,比如優先級,PGID等等。因為進程池在服務器啟動之初就創建好了,所以他們沒有打開不必要的文件描述符(從父進程繼承而來),也不會錯誤地使用大塊的堆內存(從父進程復制得到)。

(2) 當有新的任務到來時,主進程將通過某種方式選擇進程池中的某一個子進程來為之服務。相對于動態創建子進程,選擇一個已經存在的子進程的代價明顯要小的多。至于主進程選擇哪個進程來為新任務服務,則有兩種方式:

①主進程使用某種算法主動選擇子進程。最簡單、最常用的算法是隨機算法和Round-Robin(輪流選取)算法,但更優秀、更智能的算法將使任務在各個工作進程中更均勻地分配、從而減輕服務器的整體壓力。

②主進程和所有子進程通過一個共享的工作隊列來同步,子進程都睡眠在該工作隊列上。當有心的任務到來時,主進程將任務添加到工作隊列中。這將喚醒正在等待任務的子進程,不過只有一個子進程獲得新任務的“接管權”,它可以從工作隊列中取出并執行之,而其他子進程將繼續睡眠在工作隊列上。

當選擇好子進程后,主進程還需要使用某種通知機制來告訴目標子進程有新進程需要處理,并傳遞必要的數據:
在父進程和子進程之間預先建立好一條管道,然后通過該管道來實現所有進程間通信。在父線程和子線程之間傳遞數據就要簡單的多,因為我們可以把這些數據定義全局的,那么他們本身就是被所有線程共享的。

2.線程池

(1)基本功能

線程池提供了一個解決外部大量用戶與服務器有限資源的矛盾,它的基本思想就是在程序 開始時就在內存中開辟一些線程, 線程的數目是 固定的,他們獨自形成一個類, 屏蔽了對外的操作, 而服務器只需要將數據包交給線程池就可以了。

當有新的客戶請求到達時 , 不是新創建一個線程為其服務 , 而是從“池子”中選擇一個空閑的線程為新的客戶請求服務 ,服務完畢后 , 線程進入空閑線程池中。如果沒有線程空閑的話, 就將數據包暫時積累 ,等待線程池內有線程空閑以后再進行處理。通過對多個任務重用已經存在的線程對象 , 降低了對線程對象創建和銷毀的開銷。當客戶請求時 , 線程對象已經存在, 可以提高請求的響應時間 , 從而整體地提高了系統服務的表現。

(2)一個線程池主要包括以下幾個組成部分:

①線程管理器:用于創建并管理線程池

②工作線程:線程池中實際執行任務的線程。在初始化線程時會預先創建好固定數目的線程在池中,這些初始化的線程一般處于空閑狀態,一般不占用CPU,占用較小的內存空間。

③任務接口:每個任務必須實現的接口,當線程池的任務隊列中有可執行任務時,被空閑的工作線程調去執行(線程的閑與忙是通過互斥量實現的,跟前面文章中的設置標志位差不多),把任務抽象出來形成接口,可以做到線程池與具體的任務無關。

④任務隊列:用來存放沒有處理的任務,提供一種緩沖機制,實現這種結構有好幾種方法,常用的是隊列,主要運用先進先出原理,另外一種是鏈表之類的數據結構,可以動態的為它分配內存空間,應用中比較靈活,下文中就是用到的鏈表。

3.實現一個線程池:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <pthread.h> #include <assert.h> /* *線程池里所有運行和等待的任務都是一個CThread_worker *由于所有任務都在鏈表里,所以是一個鏈表結構 */ typedef struct worker { /*回調函數,任務運行時會調用此函數,注意也可聲明成其它形式*/ void *(*process) (void *arg); void *arg;/*回調函數的參數*/ struct worker *next; } CThread_worker; /*線程池結構*/ typedef struct { pthread_mutex_t queue_lock; pthread_cond_t queue_ready; /*鏈表結構,線程池中所有等待任務*/ CThread_worker *queue_head; /*是否銷毀線程池*/ int shutdown; pthread_t *threadid; /*線程池中允許的活動線程數目*/ int max_thread_num; /*當前等待隊列的任務數目*/ int cur_queue_size; } CThread_pool; int pool_add_worker (void *(*process) (void *arg), void *arg); void *thread_routine (void *arg); //share resource static CThread_pool *pool = NULL; void pool_init (int max_thread_num) { pool = (CThread_pool *) malloc (sizeof (CThread_pool)); pthread_mutex_init (&(pool->queue_lock), NULL); pthread_cond_init (&(pool->queue_ready), NULL); pool->queue_head = NULL; pool->max_thread_num = max_thread_num; pool->cur_queue_size = 0; pool->shutdown = 0; pool->threadid = (pthread_t *) malloc (max_thread_num * sizeof (pthread_t)); int i = 0; for (i = 0; i < max_thread_num; i++) { pthread_create (&(pool->threadid[i]), NULL, thread_routine,NULL); } } /*向線程池中加入任務*/ int pool_add_worker (void *(*process) (void *arg), void *arg) { /*構造一個新任務*/ CThread_worker *newworker = (CThread_worker *) malloc (sizeof (CThread_worker)); newworker->process = process; newworker->arg = arg; newworker->next = NULL;/*別忘置空*/ pthread_mutex_lock (&(pool->queue_lock)); /*將任務加入到等待隊列中*/ CThread_worker *member = pool->queue_head; if (member != NULL) { while (member->next != NULL) member = member->next; member->next = newworker; } else { pool->queue_head = newworker; } assert (pool->queue_head != NULL); pool->cur_queue_size++; pthread_mutex_unlock (&(pool->queue_lock)); /*好了,等待隊列中有任務了,喚醒一個等待線程; 注意如果所有線程都在忙碌,這句沒有任何作用*/ pthread_cond_signal (&(pool->queue_ready)); return 0; } /*銷毀線程池,等待隊列中的任務不會再被執行,但是正在運行的線程會一直 把任務運行完后再退出*/ int pool_destroy () { if (pool->shutdown) return -1;/*防止兩次調用*/ pool->shutdown = 1; /*喚醒所有等待線程,線程池要銷毀了*/ pthread_cond_broadcast (&(pool->queue_ready)); /*阻塞等待線程退出,否則就成僵尸了*/ int i; for (i = 0; i < pool->max_thread_num; i++) pthread_join (pool->threadid[i], NULL); free (pool->threadid); /*銷毀等待隊列*/ CThread_worker *head = NULL; while (pool->queue_head != NULL) { head = pool->queue_head; pool->queue_head = pool->queue_head->next; free (head); } /*條件變量和互斥量也別忘了銷毀*/ pthread_mutex_destroy(&(pool->queue_lock)); pthread_cond_destroy(&(pool->queue_ready)); free (pool); /*銷毀后指針置空是個好習慣*/ pool=NULL; return 0; } void *thread_routine (void *arg) { printf ("starting thread 0x%x\n", pthread_self ()); while (1) { pthread_mutex_lock (&(pool->queue_lock)); /*如果等待隊列為0并且不銷毀線程池,則處于阻塞狀態; 注意 pthread_cond_wait是一個原子操作,等待前會解鎖,喚醒后會加鎖*/ while (pool->cur_queue_size == 0 && !pool->shutdown) { printf ("thread 0x%x is waiting\n", pthread_self ()); pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock)); } /*線程池要銷毀了*/ if (pool->shutdown) { /*遇到break,continue,return等跳轉語句,千萬不要忘記先解鎖*/ pthread_mutex_unlock (&(pool->queue_lock)); printf ("thread 0x%x will exit\n", pthread_self ()); pthread_exit (NULL); } printf ("thread 0x%x is starting to work\n", pthread_self ()); /*assert是調試的好幫手*/ assert (pool->cur_queue_size != 0); assert (pool->queue_head != NULL); /*等待隊列長度減去1,并取出鏈表中的頭元素*/ pool->cur_queue_size--; CThread_worker *worker = pool->queue_head; pool->queue_head = worker->next; pthread_mutex_unlock (&(pool->queue_lock)); /*調用回調函數,執行任務*/ (*(worker->process)) (worker->arg); free (worker); worker = NULL; } /*這一句應該是不可達的*/ pthread_exit (NULL); } // 下面是測試代碼 void *myprocess (void *arg) { printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg); sleep (1);/*休息一秒,延長任務的執行時間*/ return NULL; } int main (int argc, char **argv) { pool_init (3);/*線程池中最多三個活動線程*/ /*連續向池中投入10個任務*/ int *workingnum = (int *) malloc (sizeof (int) * 10); int i; for (i = 0; i < 10; i++) { workingnum[i] = i; pool_add_worker (myprocess, &workingnum[i]); } /*等待所有任務完成*/ sleep (5); /*銷毀線程池*/ pool_destroy (); free (workingnum); return 0; }

結果如圖:

調研結果來源于:
http://blog.csdn.net/al_xin/article/details/39258067
http://blog.csdn.net/hubi0952/article/details/8045094

總結

以上是生活随笔為你收集整理的Linux进程池、线程池调研的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。