版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、并發(fā)服務(wù)器目錄n服務(wù)器分類技術(shù)n進(jìn)程與線程n多進(jìn)程服務(wù)器n多線程服務(wù)器并發(fā)服務(wù)器服務(wù)器分類n按連接類型分類n面向連接的服務(wù)器(如tcp)n面向無連接的服務(wù)器(如udp)n按處理方式分類n迭代服務(wù)器n并發(fā)服務(wù)器迭代服務(wù)器 vs. 并發(fā)服務(wù)器綁定地址監(jiān)聽連接接收連接處理連接斷開連接接收請求處理請求返回響應(yīng)綁定地址監(jiān)聽連接接收連接創(chuàng)建子進(jìn)程關(guān)閉連接套接字處理連接關(guān)閉連接套接字終止子進(jìn)程關(guān)閉監(jiān)聽套接字服務(wù)器主進(jìn)程服務(wù)器子進(jìn)程TCP迭代服務(wù)器TCP并發(fā)服務(wù)器“進(jìn)程”基本概念n進(jìn)程定義了一個(gè)計(jì)算的基本單元,可以認(rèn)為是一個(gè)程序的一次運(yùn)行。它是一個(gè)動(dòng)態(tài)實(shí)體,是獨(dú)立的任務(wù)。它擁有獨(dú)立的地址空間、執(zhí)行堆棧、文件描
2、述符等。n每個(gè)進(jìn)程擁有獨(dú)立的地址空間,進(jìn)程間正常情況下,互不影響,一個(gè)進(jìn)程的崩潰不會(huì)造成其他進(jìn)程的崩潰。n當(dāng)進(jìn)程間共享某一資源時(shí),需注意兩個(gè)問題:同步問題和通信問題。創(chuàng)建進(jìn)程#include #include pid_t fork(void)返回:父進(jìn)程中返回子進(jìn)程的進(jìn)程返回:父進(jìn)程中返回子進(jìn)程的進(jìn)程ID, 子進(jìn)程返回子進(jìn)程返回0, -1出錯(cuò)出錯(cuò)nfork后,子進(jìn)程和父進(jìn)程繼續(xù)執(zhí)行后,子進(jìn)程和父進(jìn)程繼續(xù)執(zhí)行fork()函數(shù)后的指令。()函數(shù)后的指令。子進(jìn)程是父進(jìn)程的副本。子進(jìn)程擁有父進(jìn)程的數(shù)據(jù)空間、子進(jìn)程是父進(jìn)程的副本。子進(jìn)程擁有父進(jìn)程的數(shù)據(jù)空間、堆棧的副本。但父、子進(jìn)程并不共享這些存儲(chǔ)空間部
3、分。堆棧的副本。但父、子進(jìn)程并不共享這些存儲(chǔ)空間部分。如果代碼段是只讀的,則父子進(jìn)程共享代碼段。如果父子如果代碼段是只讀的,則父子進(jìn)程共享代碼段。如果父子進(jìn)程同時(shí)對同一文件描述字操作,而又沒有任何形式的同進(jìn)程同時(shí)對同一文件描述字操作,而又沒有任何形式的同步,則會(huì)出現(xiàn)混亂的狀況;步,則會(huì)出現(xiàn)混亂的狀況;n父進(jìn)程中調(diào)用父進(jìn)程中調(diào)用fork之前打開的所有描述字在函數(shù)之前打開的所有描述字在函數(shù)fork返回返回之后子進(jìn)程會(huì)得到一個(gè)副本。之后子進(jìn)程會(huì)得到一個(gè)副本。fork后,父子進(jìn)程均需要將后,父子進(jìn)程均需要將自己不使用的描述字關(guān)閉,有兩方面的原因:(自己不使用的描述字關(guān)閉,有兩方面的原因:(1)以免)以
4、免出現(xiàn)不同步的情況;(出現(xiàn)不同步的情況;(2)最后能正常關(guān)閉描述字最后能正常關(guān)閉描述字#include#includemain() int i, sum; sum = 0; for(i =0;i 0) printf(parent running .n); printf(parent exitn); exit(0); else printf(fork error.n); exit(1); 創(chuàng)建進(jìn)程(cont.)#include #include pid_t vfork(void);n該系統(tǒng)調(diào)用基本上與該系統(tǒng)調(diào)用基本上與fork相同,在相同,在BSD3.0中開始出現(xiàn),主中開始出現(xiàn),主要為了解決要為
5、了解決fork昂貴的開銷。昂貴的開銷。n兩者的基本區(qū)別在于當(dāng)使用兩者的基本區(qū)別在于當(dāng)使用vfork()創(chuàng)建新進(jìn)程時(shí),父進(jìn)程創(chuàng)建新進(jìn)程時(shí),父進(jìn)程將被暫時(shí)阻塞,而子進(jìn)程則可以借用父進(jìn)程的地址空間。這將被暫時(shí)阻塞,而子進(jìn)程則可以借用父進(jìn)程的地址空間。這個(gè)奇特狀態(tài)將持續(xù)直到子進(jìn)程退出,至此父進(jìn)程才繼續(xù)執(zhí)行。個(gè)奇特狀態(tài)將持續(xù)直到子進(jìn)程退出,至此父進(jìn)程才繼續(xù)執(zhí)行。 因此,子進(jìn)程需小心處理共享變量。因此,子進(jìn)程需小心處理共享變量。運(yùn)行的結(jié)果:終止進(jìn)程終止進(jìn)程n進(jìn)程的終止存在兩個(gè)可能:進(jìn)程的終止存在兩個(gè)可能:n父進(jìn)程先于子進(jìn)程終止(父進(jìn)程先于子進(jìn)程終止(init進(jìn)程領(lǐng)養(yǎng))進(jìn)程領(lǐng)養(yǎng))n子進(jìn)程先于主進(jìn)程終止子進(jìn)程
6、先于主進(jìn)程終止n對于后者,系統(tǒng)內(nèi)核為子進(jìn)程保留一定的狀態(tài)對于后者,系統(tǒng)內(nèi)核為子進(jìn)程保留一定的狀態(tài)信息:進(jìn)程信息:進(jìn)程ID、終止?fàn)顟B(tài)、終止?fàn)顟B(tài)、CPU時(shí)間等;當(dāng)時(shí)間等;當(dāng)父進(jìn)程調(diào)用父進(jìn)程調(diào)用wait或或waitpid函數(shù)時(shí),獲取這些函數(shù)時(shí),獲取這些信息;(什么叫信息;(什么叫“僵尸進(jìn)程僵尸進(jìn)程”?)?)n當(dāng)子進(jìn)程正?;虍惓=K止時(shí),系統(tǒng)內(nèi)核向其父當(dāng)子進(jìn)程正?;虍惓=K止時(shí),系統(tǒng)內(nèi)核向其父進(jìn)程發(fā)送進(jìn)程發(fā)送SIGCHLD信號(hào);缺省情況下,父進(jìn)信號(hào);缺省情況下,父進(jìn)程忽略該信號(hào),或者提供一個(gè)該信號(hào)發(fā)生時(shí)即程忽略該信號(hào),或者提供一個(gè)該信號(hào)發(fā)生時(shí)即被調(diào)用的函數(shù)。被調(diào)用的函數(shù)。進(jìn)程的狀態(tài)n就緒:進(jìn)程準(zhǔn)備運(yùn)行,但
7、還沒有得到CPU。根據(jù)調(diào)度算法決定將CPU分配給某個(gè)進(jìn)程。n運(yùn)行:進(jìn)程正在運(yùn)行(即占用CPU)n等待:進(jìn)程正在等待某個(gè)事件的發(fā)生,如:輸入輸出的完成、子進(jìn)程的退出、進(jìn)程睡眠期的結(jié)束。n被交換:進(jìn)程準(zhǔn)備運(yùn)行,但可能由于需要更多的內(nèi)存而當(dāng)前卻沒有足夠的可用內(nèi)存,因此被暫時(shí)存放在硬盤(交換空間)上。n僵死:一個(gè)已經(jīng)終止,但是其父進(jìn)程尚未對其進(jìn)行善后處理的進(jìn)程。 終止進(jìn)程(續(xù))終止進(jìn)程(續(xù))#include void exit(int status);n本函數(shù)終止調(diào)用進(jìn)程。關(guān)閉所有子進(jìn)程打開的描述本函數(shù)終止調(diào)用進(jìn)程。關(guān)閉所有子進(jìn)程打開的描述符,向父進(jìn)程發(fā)送符,向父進(jìn)程發(fā)送SIGCHLD信號(hào),并返回狀態(tài)
8、。信號(hào),并返回狀態(tài)。獲取子進(jìn)程終止信息獲取子進(jìn)程終止信息#include #include pid_t wait(int *stat_loc); 返回:終止子進(jìn)程的返回:終止子進(jìn)程的ID成功;成功;-1出錯(cuò);出錯(cuò);stat_loc存儲(chǔ)存儲(chǔ)子進(jìn)程的終止?fàn)顟B(tài)(一個(gè)整數(shù));子進(jìn)程的終止?fàn)顟B(tài)(一個(gè)整數(shù));n如果沒有終止的子進(jìn)程,但是有一個(gè)或多個(gè)正在執(zhí)如果沒有終止的子進(jìn)程,但是有一個(gè)或多個(gè)正在執(zhí)行的子進(jìn)程,則該函數(shù)將堵塞,直到有一個(gè)子進(jìn)程行的子進(jìn)程,則該函數(shù)將堵塞,直到有一個(gè)子進(jìn)程終止或者終止或者wait被信號(hào)中斷時(shí),被信號(hào)中斷時(shí),wait返回。返回。n當(dāng)調(diào)用該系統(tǒng)調(diào)用時(shí),如果有一個(gè)子進(jìn)程已經(jīng)終止,當(dāng)調(diào)
9、用該系統(tǒng)調(diào)用時(shí),如果有一個(gè)子進(jìn)程已經(jīng)終止,則該系統(tǒng)調(diào)用立即返回,并釋放子進(jìn)程所有資源。則該系統(tǒng)調(diào)用立即返回,并釋放子進(jìn)程所有資源。獲取子進(jìn)程終止信息獲取子進(jìn)程終止信息使用wait()函數(shù)可能會(huì)出現(xiàn)一個(gè)問題SIGCHLD服務(wù)器父進(jìn)程服務(wù)器父進(jìn)程服務(wù)器子進(jìn)程服務(wù)器子進(jìn)程服務(wù)器子進(jìn)程服務(wù)器子進(jìn)程服務(wù)器子進(jìn)程服務(wù)器子進(jìn)程客戶客戶FINFINFINSIGCHLDSIGCHLD由于由于linux信號(hào)不排隊(duì),在信號(hào)不排隊(duì),在SIGCHLD信號(hào)同時(shí)到來后,信信號(hào)同時(shí)到來后,信號(hào)處理程序中調(diào)用了號(hào)處理程序中調(diào)用了wait函數(shù),其只執(zhí)行一次,這樣將留函數(shù),其只執(zhí)行一次,這樣將留下下2個(gè)僵尸進(jìn)程??梢允褂脗€(gè)僵尸進(jìn)程
10、。可以使用waitpid函數(shù)解決這個(gè)問題。函數(shù)解決這個(gè)問題。獲取子進(jìn)程終止信息獲取子進(jìn)程終止信息pid_t waitpid(pid_t pid, int *stat_loc, int options); 返回:終止子進(jìn)程的返回:終止子進(jìn)程的ID成功;成功;-1出錯(cuò);出錯(cuò);stat_loc存儲(chǔ)存儲(chǔ)子進(jìn)程的終止?fàn)顟B(tài);子進(jìn)程的終止?fàn)顟B(tài);n當(dāng)當(dāng)pid=-1,option=0時(shí),該函數(shù)等同于時(shí),該函數(shù)等同于wait,否則,否則由參數(shù)由參數(shù)pid和和option共同決定函數(shù)行為,其中共同決定函數(shù)行為,其中pid參參數(shù)意義如下:數(shù)意義如下:n-1:要求知道任何一個(gè)子進(jìn)程的返回狀態(tài)(等待第一:要求知道任何一個(gè)
11、子進(jìn)程的返回狀態(tài)(等待第一個(gè)終止的子進(jìn)程);個(gè)終止的子進(jìn)程);n0:要求知道進(jìn)程號(hào)為:要求知道進(jìn)程號(hào)為pid的子進(jìn)程的狀態(tài);的子進(jìn)程的狀態(tài);n0)printf(“child %d terminatedn”,pid);waitpid函數(shù)用法pid_t pid;if (pid=fork() 0) /* parent process */int child_status; waitpid(pid, &child_status, 0);else if ( pid = 0 ) /* child process */exit(0);else /* fork error */printf(“fork
12、 error.n”);exit(1);程序例子:程序例子:#include #include #include int main(void) pid_t pid; int status; if (pid = fork() = 0) sleep(1); printf(child running.n); printf(child sleeping.n); printf(child dead.n); exit(0); else if ( pid 0) printf(parent running .n); waitpid(pid, &status,0); printf(parent is ru
13、nningn); printf(parent exitn); else printf(fork error.n); exit(1); 多進(jìn)程并發(fā)服務(wù)器狀態(tài)圖服務(wù)器客戶connect()函數(shù)listenfd客戶/服務(wù)器狀態(tài)圖(調(diào)用accept函數(shù)時(shí))連接請求多進(jìn)程并發(fā)服務(wù)器狀態(tài)圖(cont.)服務(wù)器服務(wù)器客戶客戶connect()函數(shù)listenfd客戶/服務(wù)器狀態(tài)圖(調(diào)用accept函數(shù)后)connfd連接建立多進(jìn)程并發(fā)服務(wù)器狀態(tài)圖(cont.)服務(wù)器(父進(jìn)程)服務(wù)器(父進(jìn)程)客戶客戶connect()函數(shù)函數(shù)listenfd客戶/服務(wù)器狀態(tài)圖(調(diào)用fork函數(shù)后)connfd連接建立連接建立
14、服務(wù)器(子進(jìn)程)listenfdconnfdfork()函數(shù)多進(jìn)程并發(fā)服務(wù)器狀態(tài)圖(cont.)服務(wù)器(父進(jìn)程)服務(wù)器(父進(jìn)程)客戶客戶connect()函數(shù)函數(shù)listenfd客戶/服務(wù)器狀態(tài)圖(父進(jìn)程關(guān)閉連接套接字,子進(jìn)程關(guān)閉監(jiān)聽套接字)連接建立服務(wù)器(子進(jìn)程)服務(wù)器(子進(jìn)程)connfd多進(jìn)程并發(fā)服務(wù)器模板int main(void)int listenfd, connfd;pid_t pid;intBACKLOG = 5;if (listenfd = socket(AF_INET, SOCK_STREAM, 0) = -1) perror(“Create socket failed.”
15、);exit(1); bind(listenfd, );listen(listenfd, BACKLOG);while(1) if (connfd = accept(sockfd, NULL, NULL) = -1) perror(“Accept error.”); exit(1); 多進(jìn)程并發(fā)服務(wù)器模板if(pid = fork() ) 0) /*parent process */ close(connfd); . continue;else if (pid = 0) /*child process */ close(lisetenfd); . exit(0);else printf(“fo
16、rk errorn”); exit(1); 一點(diǎn)說明n從以上模板看出,產(chǎn)生新的子進(jìn)程后,父進(jìn)程要關(guān)閉連接套接字,而子進(jìn)程要關(guān)閉監(jiān)聽套接字,主要原因是:n關(guān)閉不需要的套接字可節(jié)省系統(tǒng)資源,同時(shí)可避免父子進(jìn)程共享這些套接字可能帶來的不可預(yù)計(jì)的后果;n另一個(gè)更重要的原因,是為了正確地關(guān)閉連接。和文件描述符一樣,每個(gè)套接字描述符都有一個(gè)“引用計(jì)數(shù)”。當(dāng)fork函數(shù)返回后,listenfd和connfd的引用計(jì)數(shù)變?yōu)?,而系統(tǒng)只有在某描述符的“引用計(jì)數(shù)”為0時(shí),才真正關(guān)閉該描述符。多進(jìn)程并發(fā)服務(wù)器實(shí)例n該實(shí)例包括服務(wù)器程序和客戶程序,具體功能如該實(shí)例包括服務(wù)器程序和客戶程序,具體功能如下:下:n服務(wù)器等
17、待客戶連接請求,連接成功后顯示客戶地址,服務(wù)器等待客戶連接請求,連接成功后顯示客戶地址,并接收該客戶的名字并顯示,然后接收來自客戶的信并接收該客戶的名字并顯示,然后接收來自客戶的信息(字符串)并顯示,然后將該字符串反轉(zhuǎn),并將結(jié)息(字符串)并顯示,然后將該字符串反轉(zhuǎn),并將結(jié)果送回客戶,之后,繼續(xù)等待接收該客戶的信息直至果送回客戶,之后,繼續(xù)等待接收該客戶的信息直至該客戶關(guān)閉連接。要求服務(wù)器具有同時(shí)處理多個(gè)客戶該客戶關(guān)閉連接。要求服務(wù)器具有同時(shí)處理多個(gè)客戶的能力。的能力。n客戶首先與服務(wù)器連接,接著接收用戶輸入客戶的名客戶首先與服務(wù)器連接,接著接收用戶輸入客戶的名字,并將該名字發(fā)送給服務(wù)器,接收用
18、戶輸入的字符字,并將該名字發(fā)送給服務(wù)器,接收用戶輸入的字符串,發(fā)送給服務(wù)器,接收服務(wù)器返回的經(jīng)處理后的字串,發(fā)送給服務(wù)器,接收服務(wù)器返回的經(jīng)處理后的字符串,并顯示之。之后,繼續(xù)等待用戶輸入直至用戶符串,并顯示之。之后,繼續(xù)等待用戶輸入直至用戶輸入輸入Ctrl+C,終止連接并退出。,終止連接并退出。多進(jìn)程并發(fā)服務(wù)器服務(wù)器#include #define PORT1234#define BACKLOG10#define MAXDATASIZE1000void process_cli(int connectfd, struct sockaddr_in client);int main(void)in
19、t listenfd, connectfd;pid_tpid;struct sockaddr_intserver, client;int sin_size;/* Create TCP Socket */if(listenfd=socket(AF_INET, SOCK_STREAM, 0)=-1) perror(Create socket failed); exit(-1); int opt = SO_REUSEADDR;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt);bzero(&server,
20、sizeof(server);server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(listenfd, (struct sockaddr *)&server, serrver)=-1) perror(Bind error); exit(-1); if (listen(listenfd, BACKLOG) = -1) perror(listen error); exit(-1); sin_size = sizeof(stru
21、ct sockaddr_in);while(1) if(connectfd = accept(listenfd, (struct sockaddr *)&client, &sin_size) = -1) perror(accept error); exit(-1); if (pid=fork()0) /* parent process */ close(connectfd); continue; else if (pid=0) /*child process*/ close(listenfd); process_cli(connectfd, client); exit(0);
22、else printf(fork errorn); exit(0); /*while()*/close(listenfd); /* close listenfd */ 多進(jìn)程并發(fā)服務(wù)器服務(wù)器void process_cli(int connectfd, struct sockaddr_in client) int num;char recvbufMAXDATASIZE, sendbufMAXDATASIZE, cli_nameMAXDATASIZE;printf(“You got a connection from %s.n”, inet_ntoa(client.sin_addr);num =
23、 recv(connectfd, cli_name, MAXDATASIZE, 0);if (num = 0) close(connectfd);printf(“cllient disconnected.n”);return;cli_namenum = 0;printf(“Client name is %s.n”,cli_name);:多進(jìn)程并發(fā)服務(wù)器服務(wù)器while (num = recv(connectfd, recvbuf, MAXDATASIZE,0) recvbufnum = 0;printf(“Received client (%s) message: %sn”, cli_name
24、, recvbuf);for(int i=0; i num ; i+)sendbufi = recvbufnum-i-1;sendbufi = 0;send(connectfd, sendbuf, strlen(sendbuf), 0);close(connectfd);多進(jìn)程并發(fā)服務(wù)器-運(yùn)行結(jié)果rootsheng sheng# ./multiproserverThe server is runningYou got a connection from 222.18.113.153.Client name is shengReceived client(sheng)message:how a
25、yYou got a connection from 127.0.0.1.Client name is limingReceived client(liming)message:abcdReceived client(sheng)message:12345n可以看出,服務(wù)器能同時(shí)為多個(gè)客戶服務(wù)??梢钥闯?,服務(wù)器能同時(shí)為多個(gè)客戶服務(wù)。(可以思考如果采用迭代服務(wù)器,結(jié)果如何?)(可以思考如果采用迭代服務(wù)器,結(jié)果如何?)多個(gè)客戶同時(shí)請求處理多進(jìn)程服務(wù)器的問題多進(jìn)程服務(wù)器的問題n傳統(tǒng)的網(wǎng)絡(luò)服務(wù)器程序大都在新的連接到達(dá)時(shí),傳統(tǒng)的網(wǎng)絡(luò)服務(wù)器程序大都在新的連接到達(dá)時(shí),fork一個(gè)子進(jìn)程來處理。雖然這種模式很
26、多年使用一個(gè)子進(jìn)程來處理。雖然這種模式很多年使用得很好,但得很好,但fork有一些問題:有一些問題:nfork是昂貴的。是昂貴的。fork時(shí)需要復(fù)制父進(jìn)程的所有資源,包時(shí)需要復(fù)制父進(jìn)程的所有資源,包括內(nèi)存映象、描述字等;目前的實(shí)現(xiàn)使用了一種寫時(shí)拷括內(nèi)存映象、描述字等;目前的實(shí)現(xiàn)使用了一種寫時(shí)拷貝(貝(copy-on-write)技術(shù),可有效避免昂貴的復(fù)制問)技術(shù),可有效避免昂貴的復(fù)制問題,但題,但fork仍然是昂貴的仍然是昂貴的;nfork子進(jìn)程后,父子進(jìn)程間、兄弟進(jìn)程間的通信需要進(jìn)子進(jìn)程后,父子進(jìn)程間、兄弟進(jìn)程間的通信需要進(jìn)程間通信程間通信IPC機(jī)制,給通信帶來了困難;機(jī)制,給通信帶來了困難
27、;n多進(jìn)程在一定程度上仍然不能有效地利用系統(tǒng)資源多進(jìn)程在一定程度上仍然不能有效地利用系統(tǒng)資源;n系統(tǒng)中進(jìn)程個(gè)數(shù)也有限制。系統(tǒng)中進(jìn)程個(gè)數(shù)也有限制?!熬€程線程”基本概念基本概念n線程是進(jìn)程內(nèi)的獨(dú)立執(zhí)行實(shí)體和調(diào)度單元,又稱為線程是進(jìn)程內(nèi)的獨(dú)立執(zhí)行實(shí)體和調(diào)度單元,又稱為“輕量級(jí)輕量級(jí)”進(jìn)程(進(jìn)程(lightwight process);創(chuàng)建線程比進(jìn)程快);創(chuàng)建線程比進(jìn)程快10100倍。一個(gè)進(jìn)程內(nèi)的所有線程共享相同的內(nèi)存空間、倍。一個(gè)進(jìn)程內(nèi)的所有線程共享相同的內(nèi)存空間、全局變量等信息(這種機(jī)制又帶來了同步問題)。而且它們?nèi)肿兞康刃畔ⅲㄟ@種機(jī)制又帶來了同步問題)。而且它們還共享以下信息:還共享以下信息:
28、 共享信息共享信息 私有信息私有信息n進(jìn)程指令進(jìn)程指令 線程線程IDn大多數(shù)數(shù)據(jù)大多數(shù)數(shù)據(jù) 寄存器集合(包括程序計(jì)數(shù)器和棧指針)寄存器集合(包括程序計(jì)數(shù)器和棧指針)n打開的文件描述字打開的文件描述字棧(用于存放局部變量)棧(用于存放局部變量)n信號(hào)處理程序和信號(hào)處置信號(hào)處理程序和信號(hào)處置errorn當(dāng)前工作目錄當(dāng)前工作目錄信號(hào)掩碼信號(hào)掩碼n用戶用戶ID和組和組ID優(yōu)先級(jí)優(yōu)先級(jí)線程調(diào)用函數(shù)(1)#include int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void *), void *a
29、rg); 返回:成功時(shí)為返回:成功時(shí)為0;出錯(cuò)時(shí)為正的;出錯(cuò)時(shí)為正的Exxx值值n當(dāng)一個(gè)程序開始運(yùn)行時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)初始線程或主線程當(dāng)一個(gè)程序開始運(yùn)行時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)初始線程或主線程的單個(gè)線程。額外線程由上述函數(shù)創(chuàng)建;的單個(gè)線程。額外線程由上述函數(shù)創(chuàng)建;n新線程由線程新線程由線程id標(biāo)識(shí):標(biāo)識(shí):tid,新線程的屬性,新線程的屬性attr包括:優(yōu)先級(jí)、包括:優(yōu)先級(jí)、初始棧大小、是否應(yīng)該是守護(hù)線程等等。線程的執(zhí)行函數(shù)和初始棧大小、是否應(yīng)該是守護(hù)線程等等。線程的執(zhí)行函數(shù)和調(diào)用參數(shù)分別是:調(diào)用參數(shù)分別是:func和和arg;n由于線程的執(zhí)行函數(shù)的參數(shù)和返回值類型均為由于線程的執(zhí)行函數(shù)的參數(shù)和返回值
30、類型均為void *,因此,因此可傳遞和返回指向任何類型的指針;可傳遞和返回指向任何類型的指針;n常見的返回錯(cuò)誤值:常見的返回錯(cuò)誤值:EAGAIN:超過了系統(tǒng)線程數(shù)目的限制。:超過了系統(tǒng)線程數(shù)目的限制。ENOMEN:沒有足夠的內(nèi)存產(chǎn)生新的線程。:沒有足夠的內(nèi)存產(chǎn)生新的線程。EINVAL:無效的屬性:無效的屬性attr值。值。例:創(chuàng)建一個(gè)線程#include #include pthread_t tid;void *ex() printf(this is a thread);main() pthread_create(&tid,NULL,ex,NULL);線程函數(shù)調(diào)用(線程函數(shù)調(diào)用(2)
31、#inlcude int pthread_join(pthread_t tid, void *status); 返回:成功時(shí)為返回:成功時(shí)為0;出錯(cuò)時(shí)為正的;出錯(cuò)時(shí)為正的Exxx值,不值,不設(shè)置設(shè)置errorn該函數(shù)類似與該函數(shù)類似與waitpid函數(shù),但必須指定等函數(shù),但必須指定等待線程的待線程的ID,該函數(shù)不能等待任意一個(gè)線程,該函數(shù)不能等待任意一個(gè)線程結(jié)束(如結(jié)束(如wait););n被等待線程必須是當(dāng)前進(jìn)程的成員,并且不被等待線程必須是當(dāng)前進(jìn)程的成員,并且不是是分離的線程分離的線程和和守護(hù)線程守護(hù)線程。pthread_t pthread_self(void); 返回:調(diào)用線程的線程返回
32、:調(diào)用線程的線程id;線程函數(shù)調(diào)用(3)#include int pthread_detach(pthread_t tid) 返回:成功時(shí)為返回:成功時(shí)為0;出錯(cuò)時(shí)為正;出錯(cuò)時(shí)為正Exxx值;值;n線程或者是可匯合的(線程或者是可匯合的(joinable)(默認(rèn)),或者)(默認(rèn)),或者是脫離的(是脫離的(detached)。當(dāng)可匯合的線程終止時(shí),)。當(dāng)可匯合的線程終止時(shí),其線程其線程id和退出狀態(tài)將保留,直到另外一個(gè)線程調(diào)用和退出狀態(tài)將保留,直到另外一個(gè)線程調(diào)用pthread_join。脫離的線程則像守護(hù)進(jìn)程,當(dāng)它終。脫離的線程則像守護(hù)進(jìn)程,當(dāng)它終止時(shí),釋放所有資源,我們不能等待它終止。止時(shí),
33、釋放所有資源,我們不能等待它終止。n該函數(shù)將指定的線程變?yōu)槊撾x的。該函數(shù)將指定的線程變?yōu)槊撾x的。 pthread_detach(pthread_self()();線程函數(shù)調(diào)用(線程函數(shù)調(diào)用(4)#include void pthread_exit(void *status); 無返回值;無返回值;n如果線程為可匯合的,將保留線程如果線程為可匯合的,將保留線程id和退出狀態(tài)供和退出狀態(tài)供pthread_join()函數(shù)調(diào)用()函數(shù)調(diào)用;n指針指針status:指向線程的退出狀態(tài)。不能指向一個(gè)局部:指向線程的退出狀態(tài)。不能指向一個(gè)局部變量,因?yàn)榫€程終止時(shí)其所有的局部變量將被撤銷;變量,因?yàn)榫€程終止
34、時(shí)其所有的局部變量將被撤銷;n還有其他兩種方法可使線程終止還有其他兩種方法可使線程終止n啟動(dòng)線程的函數(shù)(啟動(dòng)線程的函數(shù)(pthread_create的第的第3個(gè)參數(shù))個(gè)參數(shù))返回。其返回值便是線程的終止?fàn)顟B(tài);返回。其返回值便是線程的終止?fàn)顟B(tài);n如果進(jìn)程的如果進(jìn)程的main函數(shù)返回,或者當(dāng)前進(jìn)程中,任一函數(shù)返回,或者當(dāng)前進(jìn)程中,任一線程調(diào)用了線程調(diào)用了exit()函數(shù),將終止該進(jìn)程中所有線()函數(shù),將終止該進(jìn)程中所有線程。程。線程函數(shù)調(diào)用(線程函數(shù)調(diào)用(5)include int pthread_once(pthread_once_t *once_control, void (*init_rou
35、tine) (void) 成功返回成功返回0,否則返回錯(cuò)誤碼,否則返回錯(cuò)誤碼 n如果本函數(shù)中,如果本函數(shù)中,once_control變量使用的初值為變量使用的初值為PTHREAD_ONCE_INIT,可保證,可保證init_routine()函數(shù)在函數(shù)在執(zhí)行序列中僅執(zhí)行一次。執(zhí)行序列中僅執(zhí)行一次。n一般在一般在init_routine函數(shù)中完成一些初始化工作。函數(shù)中完成一些初始化工作。 nLinuxThreads使用互斥鎖和條件變量保證由使用互斥鎖和條件變量保證由pthread_once()指定的函數(shù)執(zhí)行且僅執(zhí)行一次,而指定的函數(shù)執(zhí)行且僅執(zhí)行一次,而once_control則表征是否執(zhí)行過。如
36、果則表征是否執(zhí)行過。如果once_control的初的初值不是值不是PTHREAD_ONCE_INIT(LinuxThreads定義為定義為0),),pthread_once()的行為就會(huì)不正常的行為就會(huì)不正常; pthread_once函數(shù)例子函數(shù)例子#include #include pthread_once_t once=PTHREAD_ONCE_INIT;void once_run(void)printf(once_run in thread %dn,pthread_self();void * child1(void *arg)int tid=pthread_self();printf
37、(thread %d entern,tid);pthread_once(&once,once_run);printf(thread %d returnsn,tid);pthread_exit(NULL); void * child2(void *arg) int tid=pthread_self(); printf(thread %d entern,tid); pthread_once(&once,once_run); printf(thread %d returnsn,tid); pthread_exit(NULL); main(void) int tid1,tid2; pr
38、intf(“hellon”); pthread_create(&tid1,NULL,child1,NULL); pthread_create(&tid2,NULL,child2,NULL); sleep(10); printf(“main thread exit”);線程函數(shù)調(diào)用(線程函數(shù)調(diào)用(6) int pthread_cancel(pthread_t tid); 返回值:成功時(shí)為0,失敗為非0; 線程可以利用“取消機(jī)制”來終止另外一個(gè)線程;線程通過向另外一個(gè)線程發(fā)送取消請求,接收到取消請求的線程根據(jù)其設(shè)置狀態(tài),作出:1)忽略該請求;2)立即終止自己;3) 延遲一段時(shí)間終止
39、自己;線程的例子線程的例子1/* thread1.c*/#include #include #include void *thread_function(void *arg) int i; for ( i=0; i5; i+) printf(Thread says hi!n); sleep(1); return NULL;int main(void) pthread_t mythread; if ( pthread_create( &mythread, NULL, thread_function, NULL) ) printf(error creating thread.); exit
40、(1); if ( pthread_join ( mythread, NULL ) ) printf(error joining thread.); exit(1); exit(0);/*gcc thread1.c -o thread1 -lpthread */線程的例子2/* thread2.c*/#include #include int myglobal=0; void *thread_function(void *arg) int i,j; for ( i=0; i5; i+) j=myglobal; j=j+1; printf(.); fflush(stdout); sleep(1)
41、; myglobal=j; return NULL;int main(void) pthread_t mythread; int i; if ( pthread_create( &mythread, NULL, thread_function, NULL) ) printf(error creating thread.); exit(1); for ( i=0; i5; i+) myglobal=myglobal+1; printf(o); fflush(stdout); sleep(1); if ( pthread_join ( mythread, NULL ) ) printf(e
42、rror joining thread.); exit(1); printf(nmyglobal equals %dn,myglobal); exit(0); 主線程和新線程都將myglobal加1 5次。結(jié)果應(yīng)是10,為什么是5?答案:新線程覆蓋了主線程所做的修改。互斥鎖 在linux系統(tǒng)中,提供一種基本的進(jìn)程同步機(jī)制互斥鎖,可以用來保護(hù)線程代碼中共享數(shù)據(jù)的完整性。n操作系統(tǒng)將保證同時(shí)只有一個(gè)線程能成功操作系統(tǒng)將保證同時(shí)只有一個(gè)線程能成功完成對一個(gè)互斥鎖的加鎖操作。完成對一個(gè)互斥鎖的加鎖操作。n如果一個(gè)線程已經(jīng)對某一互斥鎖進(jìn)行了加如果一個(gè)線程已經(jīng)對某一互斥鎖進(jìn)行了加鎖,其他線程只有等待該線程
43、完成對這一鎖,其他線程只有等待該線程完成對這一互斥鎖解鎖后,才能完成加鎖操作?;コ怄i解鎖后,才能完成加鎖操作?;コ怄i函數(shù)pthread_mutex_lock(pthread_mutex_t *mptr) 返回:成功0,否則返回錯(cuò)誤碼nmptr:指向互斥鎖的指針。n該函數(shù)接受一個(gè)指向互斥鎖的指針作為參數(shù)并將其鎖定。如果互斥鎖已經(jīng)被鎖定,調(diào)用者將進(jìn)入睡眠狀態(tài)。函數(shù)返回時(shí),將喚醒調(diào)用者。n如果互斥鎖是靜態(tài)分配的,就將mptr初始化為常值PTHREAD_MUTEX_INITIALIZER。 pthread_mutex_unlock(pthread_mutex_t *mptr) 用于互斥鎖解鎖操作。 返
44、回:成功0,否則返回錯(cuò)誤碼改進(jìn)的程序#include #include #include #include int myglobal;pthread_mutex_t mymutex=PTHREAD_MUTEX_INITIALIZER; void *thread_function(void *arg) int i,j; for ( i=0; i5; i+) pthread_mutex_lock(&mymutex); j=myglobal; j=j+1; printf(.); fflush(stdout); sleep(1); myglobal=j; pthread_mutex_unloc
45、k(&mymutex); return NULL;int main(void) pthread_t mythread; int i; if ( pthread_create( &mythread, NULL, thread_function, NULL) ) printf(error creating thread.); abort(); for ( i=0; i connfd;info.other = (ARG *)arg) - other;/這種方法有問題,對一個(gè)客戶可以工作,但多個(gè)客戶則可能出現(xiàn)問題。這種方法有問題,對一個(gè)客戶可以工作,但多個(gè)客戶則可能出現(xiàn)問題。 通過分配arg的空間來傳遞n主
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025版土建項(xiàng)目施工人員勞動(dòng)合同范本9篇
- 2025年倉儲(chǔ)果蔬存儲(chǔ)合同
- 2025年智能社區(qū)內(nèi)新型消費(fèi)體驗(yàn)商鋪?zhàn)赓U合同2篇
- 2025年分銷代理合作模板書
- 2025年醫(yī)療支持服務(wù)合作協(xié)議
- 2025年主題公寓租賃協(xié)議
- 2025年危險(xiǎn)品運(yùn)輸報(bào)關(guān)報(bào)檢協(xié)議
- 2025年作品使用授權(quán)合同
- 2025版外墻內(nèi)保溫系統(tǒng)施工與節(jié)能監(jiān)測合同3篇
- 2025版信用卡醫(yī)療借款服務(wù)協(xié)議3篇
- 安全常識(shí)課件
- 河北省石家莊市2023-2024學(xué)年高一上學(xué)期期末聯(lián)考化學(xué)試題(含答案)
- 小王子-英文原版
- 新版中國食物成分表
- 2024年山東省青島市中考生物試題(含答案)
- 河道綜合治理工程技術(shù)投標(biāo)文件
- 專題24 短文填空 選詞填空 2024年中考英語真題分類匯編
- 再生障礙性貧血課件
- 產(chǎn)后抑郁癥的護(hù)理查房
- 2024年江蘇護(hù)理職業(yè)學(xué)院高職單招(英語/數(shù)學(xué)/語文)筆試歷年參考題庫含答案解析
- 電能質(zhì)量與安全課件
評(píng)論
0/150
提交評(píng)論