在我們之前所講述過的以poll方式實現tcp伺服器流程,我們仔細研究一下會發現,客戶端的資料我們還是以序列的方式來處理的。由此我們提出了以多程序或者多執行緒的方式來加以實現是不是會更好。
比如採用多程序的方式
但是這種方式還是會有bug出現,比如有僵死程序的情況出現和建立程序的代價很大等情況發生。此處**可以寫成如下:
pid_t pid =
fork()
;assert
(pid !=-1
)if(pid ==0)
如果採用多執行緒的方式,此處**可以寫成如下:
執行結果如下:struct pthread_data
void
*pthread_fun
(void
* arg)
在程式開始時,通過pthread_create建立5個執行緒
定義乙個陣列來儲存檔案描述符供所有執行緒共享。對這個全域性陣列有包括初始化、插入、獲取等函式操作。
思考:如果主線程接收多個客戶端太快,並且多個客戶端同時獲取了乙個檔案描述符怎麼辦?
採取同步機制來控制它,讓插入和獲取函式實現互斥,保證同時只能有乙個執行緒訪問。所以我們使用互斥量pthread_mutex_t mutex,在進入插入函式時加鎖pthread_mutex_lock(&mutex),退出時取鎖pthread_mutex_unlock(&mutex)獲取函式同理
建立時必須指定執行緒的入口位址,一旦建立成功,執行緒就自行啟動執行,執行緒必須阻塞某乙個條件,等待主線程接收到客戶端連線時喚醒
主線程執行accept等待客戶端鏈結,如果有鏈結,則接收連線後,將此連線傳遞給函式執行緒,喚醒乙個池中的執行緒來處理此連線
3、流程圖
具體參見博文執行緒池
具體**實現如下:
#define _gnu_source
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eventsize 128
#define pthreadnum 5
// 執行緒池中線程的數量
#define arraysize 128
pthread_t id[pthreadnum]
;pthread_mutex_t mutex;
//定義訊號量
sem_t sem;
int buff[arraysize]
;void
initbuff()
}void
addbuff
(int fd)}if
(i == arraysize)
pthread_mutex_unlock
(&mutex);}
// 獲取乙個有效的檔案描述符並將buff中的位置置為-1
intgetbuff()
}pthread_mutex_unlock
(&mutex)
;return c;
}// 所有的函式執行緒的主邏輯: 1、為乙個客戶端服務 2、處理一次就緒事件 因為第一種方式雖然簡單,但是可能出現這個客戶端一直不發資料卻一直占用這個執行緒的情況。所以採用第二種相對較好的處理方式
void
*work_pthread
(void
*arg)
while(1
);int n =
recv
(fd, buff,
127,0)
;if(n ==-1
&& errno == eagain)
printf
("%d::%d: %s\n"
,index, fd, buff);}
send
(fd,
"ok",2
,0);
}}//建立執行緒
void
createpthread()
}int
createsocket()
void
getnewlink
(int fd,
int epfd)
printf
("get new link success\n");
int old_option =
fcntl
(c, f_getfl)
;int new_option = old_option | o_nonblock;
fcntl
(c, f_setfl, new_option)
;struct epoll_event event;
event.data.fd = c;
event.events = epollin | epollrdhup | epollet;
//事件關注的型別
int res =
epoll_ctl
(epfd, epoll_ctl_add, c,
&event)
;assert
(res !=-1
);}void
closelink
(int fd,
int epfd)
void
dealreadyevent
(int epfd,
struct epoll_event *events,
int n,
int listenfd)
else
//普通的檔案描述符
else
//有資料到達,把其交付給工作執行緒處理}}
}int
main()
//處理就緒的事件,發現就緒事件扔給工作執行緒處理
dealreadyevent
(epfd, events, n, listenfd);}
exit(0);}
高效能伺服器程式設計 程序池 執行緒池
高效能伺服器程式設計主要分為多程序和多執行緒 程序池和執行緒池,用來處理乙個服務程式能夠同時處理多個客戶連線的問題。我們首先回顧下多程序和多執行緒的知識,因為程序池和執行緒池是在這個基礎上進行改進的,也是伺服器用的比較多的。多程序 accept 建立子程序,由子程序和客戶端通訊。父程序繼續接受客戶連...
高效能伺服器程式設計 程序池或執行緒池
一般來說,伺服器的硬體資源相對充裕,很多時候都用空間換時間的方法來提高伺服器的效能,不惜浪費大量的空間資源來換取伺服器的執行效率。具體做法 提前申請大量的資源,以備不時之需以及重複使用。這就是池的概念 池其實就是一組資源的集合。靜態資源分配 這組資源在伺服器啟動之初,就已經被建立並初始化 動態資源分...
執行緒池實現高效能伺服器
為了改善多程序和多執行緒實現伺服器不停地建立刪除程序或執行緒給系統帶來的負擔,引進了執行緒池,程序池來改善此種情況,此處以執行緒池為例。執行緒池的優勢 1 建立的程序或者執行緒是有限的,伺服器的系統代價比較小,一般不會到達系統限制的值。2 伺服器不需要頻繁的建立 銷毀程序或者執行緒,只在伺服器啟動時...