Linux多任務(wù)多線程編程-_第1頁
Linux多任務(wù)多線程編程-_第2頁
Linux多任務(wù)多線程編程-_第3頁
Linux多任務(wù)多線程編程-_第4頁
Linux多任務(wù)多線程編程-_第5頁
已閱讀5頁,還剩50頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1多進(jìn)程、多線程編程--Linux下多任務(wù)2主要內(nèi)容1.什么是多任務(wù)(1)進(jìn)程級(jí)多任務(wù)(2)線程級(jí)多任務(wù)(3)多任務(wù)處理的特點(diǎn)2.進(jìn)程(1)進(jìn)程的概念(2)文件描述符共享(3)Vfork()函數(shù)(4)exec()函數(shù)族(5)執(zhí)行新程序(6)進(jìn)程的終止(7)進(jìn)程的退出狀態(tài)(8)進(jìn)程的通信31.什么是多任務(wù)當(dāng)操作系統(tǒng)使用某種策略允許兩個(gè)或更多進(jìn)程并發(fā)共享一個(gè)CPU時(shí),它稱做多任務(wù)運(yùn)行,或多道程序運(yùn)行。在規(guī)定的時(shí)間片周期或某些事情發(fā)生前,一直執(zhí)行某個(gè)進(jìn)程。然后,操作系統(tǒng)切換到另一個(gè)進(jìn)程。這種切換十分迅速,給人一種這些進(jìn)程是同時(shí)執(zhí)行的錯(cuò)覺。而事實(shí)上,同一時(shí)刻在一個(gè)CPU上只能激活一個(gè)進(jìn)程。這種進(jìn)程間的切換在所有進(jìn)程完成前一直進(jìn)行。并發(fā)共享策略決定何時(shí)切換進(jìn)程。改策略由操作系統(tǒng)或其他進(jìn)程強(qiáng)制執(zhí)行。多任務(wù)可以分為三個(gè)級(jí)別:對(duì)話級(jí)、進(jìn)程級(jí)、線程級(jí)。4(1)進(jìn)程級(jí)多任務(wù)在對(duì)話中可以并發(fā)激活多個(gè)進(jìn)程,這些進(jìn)程相互合作來完成一個(gè)最終目標(biāo)。所有的進(jìn)程共享CPU運(yùn)行,一個(gè)進(jìn)程運(yùn)行一段時(shí)間,然后另一個(gè)進(jìn)程再運(yùn)行一段時(shí)間。操作系統(tǒng)控制進(jìn)程之間的轉(zhuǎn)換,直到所有的進(jìn)程運(yùn)行完成。對(duì)于這樣一種多個(gè)進(jìn)程并發(fā)執(zhí)行的多任務(wù)實(shí)現(xiàn)方式,稱作進(jìn)程級(jí)多任務(wù)。5進(jìn)程是運(yùn)行著的程序,是操作系統(tǒng)執(zhí)行任務(wù)的基本單位。進(jìn)程具備文本、數(shù)據(jù)和堆棧片段,以及它自己的資源。資源可以是文件、對(duì)象句柄、設(shè)備、信號(hào)量、互斥量、管道,等等。操作系統(tǒng)管理進(jìn)程運(yùn)行出錯(cuò)不會(huì)影響到別的進(jìn)程運(yùn)行。兩個(gè)進(jìn)程之間可以通過管道等方式通信,或者通過信號(hào)量的工具同步運(yùn)行。因此,進(jìn)程是實(shí)現(xiàn)多任務(wù)處理的核心單元。什么是進(jìn)程?6(2)線程級(jí)多任務(wù)進(jìn)程完成單獨(dú)的任務(wù),每個(gè)任務(wù)又可能有自己的控制流程。這些流程由輕量級(jí)的進(jìn)程構(gòu)成,稱作線程。進(jìn)程的線程并發(fā)執(zhí)行稱作線程級(jí)多任務(wù)。7在窗口系統(tǒng)中每時(shí)每刻都在進(jìn)行著上下文切換,而進(jìn)程級(jí)的上下文切換代價(jià)十分昂貴,頻繁地切換不但不能體現(xiàn)多任務(wù)系統(tǒng)的優(yōu)勢(shì),反而降低了系統(tǒng)的整體反應(yīng)速度。線程是輕量級(jí)的進(jìn)程,它由進(jìn)程創(chuàng)建,并與創(chuàng)建它的進(jìn)程工作在同一內(nèi)存空間中,不但可以與同一進(jìn)程中的其他線程共享數(shù)據(jù)和文件描述符,而且線程間的切換過程也是十分快捷和低成本的。因此越來越多的多任務(wù)處理在底層都采取線程來實(shí)現(xiàn)。你的程序選擇進(jìn)程?還是線程?8(3)多任務(wù)處理的特點(diǎn)

對(duì)話間的多任務(wù)是一個(gè)高級(jí)別的多任務(wù),它受用戶控制。進(jìn)程間的多任務(wù)以及多線程在低級(jí)別上實(shí)現(xiàn),由設(shè)計(jì)它的程序員控制。程序員創(chuàng)建進(jìn)程,并決定每個(gè)進(jìn)程的線程數(shù),任務(wù)的優(yōu)先權(quán),以及什么時(shí)候掛起、什么時(shí)候終止。92、開發(fā)多進(jìn)程程序(1)進(jìn)程的概念:一般把進(jìn)程定義成正在運(yùn)行的程序的實(shí)例,簡單的說,進(jìn)程就是一個(gè)正在運(yùn)行的程序。10(2)進(jìn)程環(huán)境和屬性在Linux系統(tǒng),C程序總是從main()函數(shù)開始的,當(dāng)用戶編寫好的程序在運(yùn)行的時(shí)候,操作系統(tǒng)會(huì)使用exec()函數(shù)運(yùn)行程序,在調(diào)用main()函數(shù)之前,exec()系統(tǒng)調(diào)用會(huì)先調(diào)用一個(gè)特殊的啟動(dòng)例程,負(fù)責(zé)從操作系統(tǒng)內(nèi)核讀取程序的命令行參數(shù),為main()函數(shù)準(zhǔn)備好工作環(huán)境。在bash下,可以執(zhí)行export查看本機(jī)支持的環(huán)境變量名稱和內(nèi)容。11(3)Linux內(nèi)核的進(jìn)程管理創(chuàng)建新進(jìn)程fork&vfork執(zhí)行程序exec…進(jìn)程終止exit…12進(jìn)程描述符每個(gè)進(jìn)程都有一個(gè)非負(fù)整型的唯一進(jìn)程ID進(jìn)程ID號(hào)為0表示調(diào)度進(jìn)程,常常被稱為交換進(jìn)程(swapper)。該進(jìn)程并不執(zhí)行任何磁盤上的程序—它是內(nèi)核的一部分,因此也被稱為系統(tǒng)進(jìn)程。進(jìn)程ID號(hào)為1通常是init進(jìn)程,在自舉過程結(jié)束時(shí)由內(nèi)核調(diào)用。init通常讀與系統(tǒng)有關(guān)的初始化文件(/etc/rc*文件),并將系統(tǒng)引導(dǎo)到一個(gè)狀態(tài)(例如多用戶)。init進(jìn)程決不會(huì)終止。它是一個(gè)普通的用戶進(jìn)程(與交換進(jìn)程不同,它不是內(nèi)核中的系統(tǒng)進(jìn)程),但是它以超級(jí)用戶特權(quán)運(yùn)行。13與進(jìn)程ID相關(guān)的API一個(gè)進(jìn)程除了能獲得操作系統(tǒng)提供的環(huán)境變量外,還具備自身的基本屬性,主要包括:進(jìn)程號(hào)(PID:ProcessID):操作系統(tǒng)通過進(jìn)程號(hào)標(biāo)識(shí)一個(gè)用戶進(jìn)程父進(jìn)程號(hào)(PPID:ParentProcessID):Linux系統(tǒng)中,除了init進(jìn)程外,所有進(jìn)程都是通過init進(jìn)程創(chuàng)建的,同時(shí),進(jìn)程又可以創(chuàng)建其他進(jìn)程,最終形成了一個(gè)倒樹形結(jié)構(gòu),每個(gè)進(jìn)程都會(huì)有自己的父進(jìn)程,通過父進(jìn)程號(hào)標(biāo)識(shí)。進(jìn)程組號(hào)(PGID:ProcessGroupID):操作系統(tǒng)允許對(duì)進(jìn)程分組,不同的進(jìn)程通過進(jìn)程組號(hào)標(biāo)識(shí)。真實(shí)用戶號(hào)(UID:UserID):用戶唯一標(biāo)識(shí)號(hào),用于標(biāo)識(shí)一個(gè)用戶。真實(shí)組號(hào)(GID:GroupID):用戶的唯一標(biāo)識(shí)號(hào),用于標(biāo)識(shí)一個(gè)用戶組。有效用戶號(hào)(EUID:EffectiveUserID):以其他用戶身份訪問文件使用。有效組號(hào)(EGID:EffectiveGroupID):以其他用戶組身份訪問文件使用14與進(jìn)程ID相關(guān)的API#include<sys/types.h>#include<unistd.h>pid_tgetpid(void);返回:調(diào)用進(jìn)程的進(jìn)程IDpid_tgetppid(void);返回:調(diào)用進(jìn)程的父進(jìn)程IDuid_tgetuid(void);返回:調(diào)用進(jìn)程的實(shí)際用戶IDuid_tgeteuid(void);返回:調(diào)用進(jìn)程的有效用戶IDgid_tgetgid(void);返回:調(diào)用進(jìn)程的實(shí)際組IDgid_tgetegid(void);返回:調(diào)用進(jìn)程的有效組ID15創(chuàng)建進(jìn)程Linux系統(tǒng)通過fork()系統(tǒng)調(diào)用創(chuàng)建一個(gè)進(jìn)程,fork()函數(shù)定義如下: #include<sys/types.h> #include<unistd.h> pid_tfork(void);返回:子進(jìn)程中為0,父進(jìn)程中為子進(jìn)程ID,出錯(cuò)為-1該函數(shù)被調(diào)用一次,但返回兩次。兩次返回的區(qū)別是子進(jìn)程的返回值是0,而父進(jìn)程的返回值則是新子進(jìn)程的進(jìn)程ID。為什么將子進(jìn)程ID返回給父進(jìn)程?16fork創(chuàng)建進(jìn)程過程17fork在內(nèi)核究竟干了那些事情子進(jìn)程和父進(jìn)程繼續(xù)執(zhí)行fork之后的指令。子進(jìn)程是父進(jìn)程的復(fù)制品。子進(jìn)程獲得父進(jìn)程數(shù)據(jù)空間、堆和棧的復(fù)制品。子進(jìn)程所擁有這些數(shù)據(jù)的拷貝。18fork的執(zhí)行流程檢查可用的內(nèi)核資源取一個(gè)空閑的進(jìn)程表項(xiàng)和唯一的PID號(hào)檢查用戶有沒有過多的運(yùn)行進(jìn)程將子進(jìn)程的狀態(tài)設(shè)為“創(chuàng)建”狀態(tài)將父進(jìn)程的進(jìn)程表項(xiàng)中的數(shù)據(jù)拷貝到子進(jìn)程表項(xiàng)中當(dāng)前目錄的索引節(jié)點(diǎn)和改變的根目錄的引用計(jì)數(shù)加1文件表中的打開文件的引用數(shù)加119fork的執(zhí)行流程(續(xù))在內(nèi)存中作父進(jìn)程上下文的拷貝在子進(jìn)程的系統(tǒng)級(jí)上下文中壓入虛擬系統(tǒng)級(jí)上下文層;If(正在執(zhí)行的進(jìn)程是父進(jìn)程)將子進(jìn)程狀態(tài)設(shè)為“就緒”狀態(tài)return子進(jìn)程的PIDelse初始化計(jì)時(shí)域return020創(chuàng)建進(jìn)程例子#include<sys/types.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>intmain(){pid_tpid;pid=fork(); //創(chuàng)建進(jìn)程if(-1==pid){ //創(chuàng)建進(jìn)程失敗printf("Errortocreatenewprocess!\n");return0;}elseif(pid==0){ //子進(jìn)程printf("Childprocess!\n");}else{ //父進(jìn)程printf("Parentprocess!ChildprocessID:%d\n",pid);}return0;}21fork出錯(cuò)的原因系統(tǒng)中已經(jīng)有了太多的進(jìn)程該實(shí)際用戶ID的進(jìn)程總數(shù)超過了系統(tǒng)限制CHILD_MAX規(guī)定了每個(gè)實(shí)際用戶ID在任一時(shí)刻可具有的最大進(jìn)程使用ulimit–a系統(tǒng)對(duì)進(jìn)程和文件描述符個(gè)數(shù)的限制。22vforkvfork函數(shù)的調(diào)用序列和返回值與fork相同,但兩者的語義不同。vfork用于創(chuàng)建一個(gè)新進(jìn)程,但是它并不將父進(jìn)程的地址空間完全復(fù)制到子進(jìn)程中,而是讓新進(jìn)程exec一個(gè)新程序vfork保證子進(jìn)程先運(yùn)行,在它調(diào)用exec或exit之后父進(jìn)程才可能被調(diào)度運(yùn)行。23(3)等待進(jìn)程結(jié)束等待進(jìn)程結(jié)束是指需要一種方法讓父進(jìn)程知道子進(jìn)程在什么時(shí)候結(jié)束。由于父進(jìn)程創(chuàng)建子進(jìn)程后,兩個(gè)進(jìn)程是無序運(yùn)行的,如果父進(jìn)程先于子進(jìn)程結(jié)束,那么子進(jìn)程就會(huì)因?yàn)檎也坏礁高M(jìn)程的進(jìn)程號(hào)而無法通知父進(jìn)程,導(dǎo)致資源無法釋放,因此需要一種方法讓父進(jìn)程知道子進(jìn)程在什么時(shí)候結(jié)束。24等待進(jìn)程結(jié)束當(dāng)一個(gè)進(jìn)程正常或異常終止時(shí),內(nèi)核就向其父進(jìn)程發(fā)送SIGCHLD信號(hào)。Linux系統(tǒng)提供了waitid()函數(shù),他們的作用是等待另外一個(gè)進(jìn)程的結(jié)束。函數(shù)定義如下:#include<sys/types.h>#include<sys/wait.h>pid_twaitpid(pid_tpid,int*statloc,intoptions);兩個(gè)函數(shù)返回:若成功則為進(jìn)程ID,若出錯(cuò)則為-125等待進(jìn)程結(jié)束#include<sys/types.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>intmain(){pid_tpid,pid_wait;intstatus;pid=fork(); //創(chuàng)建子進(jìn)程if(-1==pid){ //檢查是否創(chuàng)建成功printf("Errortocreatenewprocess!\n");return0;}elseif(pid==0){ //子進(jìn)程printf("Childprocess!\n");}else{ //父進(jìn)程printf("Parentprocess!ChildprocessID:%d\n",pid);pid_wait=waitpid(pid,&status,0); //參數(shù)0表示,如果沒有子進(jìn)程則立即返回,否則等待指定進(jìn)程號(hào)的子進(jìn)程printf("Childprocess%dreturned!\n",pid_wait);}return0;}26退出進(jìn)程Linux提供了幾個(gè)退出進(jìn)程相關(guān)的函數(shù)exit()、_exit()、atexit()和on_exit()。exit()函數(shù)的作用是退出當(dāng)前進(jìn)程,并且盡可能釋放當(dāng)前進(jìn)程占用的資源。_exit()函數(shù)作用也是退出當(dāng)前進(jìn)程,但是并不試圖釋放進(jìn)程占用的資源。atexit()函數(shù)和on_exit()函數(shù)作用都是為程序退出時(shí)指定調(diào)用用戶的代碼,區(qū)別在于on_exit()函數(shù)可以為設(shè)定的用戶函數(shù)設(shè)定參數(shù)。這幾個(gè)函數(shù)的定義:#include<stdlib.h>intatexit(void(*function)(void));inton_exit(void(*function)(int,void*),void*arg);voidexit(intstatus);#include<unistd.h>void_exit(intstatus);27退出進(jìn)程include<stdio.h>#include<stdlib.h>#include<unistd.h>voidbye(void)//退出時(shí)回調(diào)的函數(shù){printf("Thatwasall,folks\n");}voidbye1(void)//退出時(shí)回調(diào)的函數(shù){printf("Thisshouldcalledfirst!\n");}intmain(){longa;inti;i=atexit(bye);//設(shè)置退出回調(diào)函數(shù)并檢查返回結(jié)果if(i!=0){fprintf(stderr,"cannotsetexitfunctionbye\n");returnEXIT_FAILURE;}i=atexit(bye1);//設(shè)置退出回調(diào)函數(shù)并檢查返回結(jié)果if(i!=0){fprintf(stderr,"cannotsetexitfunctionbye1\n");returnEXIT_FAILURE;}returnEXIT_SUCCESS;}28常用進(jìn)程間通信的方法Linux提供了多種進(jìn)程間通信的方法,常見的包括管道、FIFO、消息隊(duì)列、信號(hào)量、共享存儲(chǔ)以及通過socket也可以實(shí)現(xiàn)不同進(jìn)程間的通信。本節(jié)簡述管道和共享內(nèi)存兩種進(jìn)程間通信方法。1.管道(及有名管道:FIFO)2.共享內(nèi)存29a.管道管道是UNIXIPC(進(jìn)程間通信)的最基本形式,并且所有UNIX系統(tǒng)都提供此種通信機(jī)制#include<unistd.h>intpipe(intfiledes[2]);返回:若成功則為0,若出錯(cuò)則為-1管道有兩種限制它們是半雙工的。數(shù)據(jù)只能在一個(gè)方向上流動(dòng)。它們只能在具有公共祖先的進(jìn)程之間使用。30fork后的半雙工管道31從父進(jìn)程到子進(jìn)程的管道32對(duì)管道的操作如果要直接存取管道,可以使用和低級(jí)的文件I/O同樣的系統(tǒng)調(diào)用,因?yàn)樵谙到y(tǒng)內(nèi)核中管道實(shí)際上是由一個(gè)有效的索引節(jié)點(diǎn)表示的。如果希望向管道中發(fā)送數(shù)據(jù),可以使用系統(tǒng)調(diào)用write(),反之,如果希望從管道中讀取數(shù)據(jù),可以使用系統(tǒng)調(diào)用read()。33創(chuàng)建管道pipe如果要使用C語言創(chuàng)建一個(gè)簡單的管道,可以使用系統(tǒng)調(diào)用pipe()。#include<unistd.h>原型:intpipe(intfd[2]);其中fd[0]為讀打開,fd[1]為寫打開;返回值:如果系統(tǒng)調(diào)用成功,返回0 如果系統(tǒng)調(diào)用失敗返回-134管道的通信實(shí)現(xiàn)#include<sys/types.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<string.h>intmain(){intfd[2];

pid_tpid;charbuf[64]="I'mparentprocess!\n";//父進(jìn)程要寫入管道的信息charline[64];if(0!=pipe(fd)){ //創(chuàng)建管道并檢查結(jié)果fprintf(stderr,"Failtocreatepipe!\n");return0;}}pid=fork(); //創(chuàng)建進(jìn)程if(pid<0){fprintf(stderr,"Failtocreateprocess!\n");return0;}elseif(0==pid){ //父進(jìn)程

close(fd[0]);

//關(guān)閉讀管道,使得父進(jìn)程只能向管道寫入數(shù)據(jù)write(fd[1],buf,strlen(buf));//寫數(shù)據(jù)到管道

close(fd[1]); //關(guān)閉寫管道}else{ //子進(jìn)程

close(fd[1]);

//關(guān)閉寫管道,使得子進(jìn)程只能從管道讀取數(shù)據(jù)read(fd[0],line,64); //從管道讀取數(shù)據(jù)printf("DATAFromParent:%s",line);close(fd[0]); //關(guān)閉讀管道}return0;父進(jìn)程關(guān)閉讀管道,子進(jìn)程關(guān)閉寫管道,管道變成了一個(gè)從父進(jìn)程到子進(jìn)程單向傳遞的數(shù)據(jù)的通道。35b.共享內(nèi)存方法共享內(nèi)存:在內(nèi)存開辟一段空間,供不同的進(jìn)程訪問。與管道相比,共享內(nèi)存不能在多個(gè)不同進(jìn)程間共享數(shù)據(jù),而且可以比管道傳送更大量的數(shù)據(jù)。36共享存儲(chǔ)共享存儲(chǔ)允許兩個(gè)或多個(gè)進(jìn)程共享一給定的存儲(chǔ)區(qū)。因?yàn)閿?shù)據(jù)不需要在客戶機(jī)和服務(wù)器之間復(fù)制,所以這是最快的一種IPC。使用共享存儲(chǔ)的唯一竅門是多個(gè)進(jìn)程之間對(duì)一給定存儲(chǔ)區(qū)的同步存取。通常,信號(hào)量被用來實(shí)現(xiàn)對(duì)共享存儲(chǔ)存取的同步。37shmgetshmget,它獲得一個(gè)共享存儲(chǔ)標(biāo)識(shí)符#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>intshmget(key_tkey,intsize,intflag);Key:關(guān)鍵字是系統(tǒng)唯一關(guān)鍵字,由ftok()生成,亦可指定;Size:需要的共享內(nèi)存的字節(jié)數(shù);Flag:存儲(chǔ)操作方式,讀,寫,創(chuàng)建通信..返回:若成功則為共享內(nèi)存ID,若出錯(cuò)則為-138shmat一旦創(chuàng)建了一個(gè)共享存儲(chǔ)段,進(jìn)程就可調(diào)用shmat將其連接到它的地址空間中.Shmat()是獲得共享內(nèi)存的起始地址.#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>void*shmat(intshmid,void*addr,intflag);Shmid:共享內(nèi)存的ID,由shmget產(chǎn)生,addr:指定共享內(nèi)存地址,若為0,表示由系統(tǒng)指定共享內(nèi)存地址,若獲取內(nèi)存成功,則返回相應(yīng)共享內(nèi)存的地址.返回:若成功則為指向共享存儲(chǔ)段的指針,若出錯(cuò)則為-139shmdt當(dāng)對(duì)共享存儲(chǔ)段的操作已經(jīng)結(jié)束時(shí),則調(diào)用shmdt脫接該段。#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>intshmdt(void*addr);addr:要分離共享內(nèi)存的地址返回:若成功則為0,若出錯(cuò)則為-140寫共享內(nèi)存操作//shm_write.c-->gcc-owshm_write.c#include<sys/ipc.h>#include<sys/shm.h>#include<sys/types.h>#include<unistd.h>intmain(){intshmid; //定義共享內(nèi)存idchar*ptr;char*shm_str="stringinasharememory";shmid=shmget(0x90,1024,SHM_W|SHM_R|IPC_CREAT|IPC_EXCL);//創(chuàng)建共享內(nèi)存if(-1==shmid)perror("createsharememory");ptr=(char*)shmat(shmid,0,0); //通過共享內(nèi)存id獲得共享內(nèi)存地址if((void*)-1==ptr)perror("getsharememory");strcpy(ptr,shm_str); //把字符串寫入共享內(nèi)存shmdt(ptr);return0;}41讀共享內(nèi)存操作//shm_read.c-->gcc-orshm_read.c#include<sys/ipc.h>#include<sys/shm.h>#include<sys/types.h>#include<unistd.h>intmain(){intshmid; //定義共享內(nèi)存idchar*ptr;shmid=shmget(0x90,1024,SHM_W|SHM_R|IPC_EXCL);//根據(jù)key獲得共享內(nèi)存idif(-1==shmid){perror("createsharememory");Return(0)}ptr=shmat(shmid,0,0); //通過共享內(nèi)存id獲得共享內(nèi)存地址if((void*)-1==ptr){perror("getsharememory");Return(0);}printf("stringinsharememory:%s\n",ptr); //打印共享內(nèi)存中的內(nèi)容shmdt(ptr);return0;}42進(jìn)程編程綜合實(shí)例//process_demo.c#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>intmain(){pid_tpid,pid_wait;intfd[2];charbuff[64],*cmd="exit";if(pipe(fd)){ //創(chuàng)建管道perror("Createpipefail!");return0;}pid=fork();if(-1==pid){perror("Createprocessfail!");return0;}elseif(0==pid){ //子進(jìn)程close(fd[1]);//關(guān)閉寫操作

printf("waitcommandfromparent!\n");while(1){read(fd[0],buff,64);if(0==strcmp(buff,cmd)){printf("recvcommandok!\n");close(fd[0]);exit(0);}}}else{ //父進(jìn)程printf("Parentprocess!childprocessid:%d\n",pid);close(fd[0]); //關(guān)閉讀操作sleep(2);printf("Sendcommandtochildprocess.\n");write(fd[1],cmd,strlen(cmd)+1); //寫入命令close(fd[1]);}return0;}43開發(fā)多線程程序1.線程的定義:線程是一種輕量級(jí)的進(jìn)程。 與進(jìn)程最大的不同是,線程沒有系統(tǒng)資源。線程是操作系統(tǒng)調(diào)度的最小單位,可以理解為一個(gè)進(jìn)程是由一個(gè)或者多個(gè)線程組成的。在操作系統(tǒng)內(nèi)核中,是按照線程作為調(diào)度單位來調(diào)度資源的。

在一個(gè)進(jìn)程內(nèi)部,多個(gè)線程之間的資源是共享的。也就是說,一個(gè)進(jìn)程內(nèi)部所有線程擁有相同的代碼地址空間和數(shù)據(jù)空間,任意線程可以訪問其他所有線程的數(shù)據(jù)。442進(jìn)程和線程對(duì)比進(jìn)程和線程有許多相似之處,但是也有許多不同:資源分配不同。工作效率不同。執(zhí)行方式不同。452進(jìn)程和線程對(duì)比463創(chuàng)建線程Linux系統(tǒng)開發(fā)多線程程序大多使用pthread庫,pthread庫是符合POSIX線程標(biāo)準(zhǔn)的一個(gè)應(yīng)用庫,提供了線程的管理和操作方法。pthread庫對(duì)線程操作的函數(shù)基本都以pthread開頭,創(chuàng)建線程的函數(shù)定義如下:#include<pthread.h>intpthread_create(pthread_t*restrictthread,constpthread_attr_t*restrictattr, void*(*start_routine)(void*),void*restrictarg);restrict為關(guān)鍵字,限制指針,thread為創(chuàng)建線程成功后的句柄,attr:為pthread_attr_t類型結(jié)構(gòu),設(shè)置線程屬性,一般為NULL;star_routine:要執(zhí)行的線程函數(shù)指針;arg:傳遞的參數(shù)(無符號(hào)指針類型的參數(shù))473創(chuàng)建線程#include<pthread.h>#include<stdio.h>#include<stdlib.h>void*thread_func(void*arg) //線程函數(shù){int*val=arg;printf("Hi,I'mathread!\n");if(NULL!=arg) //如果參數(shù)不為空,打印參數(shù)內(nèi)容printf("argumentset:%d\n",*val);while(1){//addyourcodehere

……..}}intmain(){

pthread_ttid; //線程IDintt_arg=100; //給線程傳入的參數(shù)值if(pthread_create(&tid,NULL,thread_func,&t_arg)) //創(chuàng)建線程perror("Failtocreatethread");

sleep(1); //睡眠1秒,等待線程執(zhí)行while(1){printf("Mainthread!\n");}return0;}48創(chuàng)建多個(gè)線程#include<pthread.h>#include<stdio.h>#include<stdlib.h>void*thread_func(void*arg) //線程函數(shù){int*val=arg;//傳遞參數(shù)printf("Hi,I'mathread!\n");if(NULL!=arg) //如果參數(shù)不為空,打印參數(shù)內(nèi)容while(1){//addyourcodehereif(NULL!=arg)printf("argumentset:%d\n",*val);}}intmain(){pthread_ttid; //線程IDpthread_ttid_2; //線程IDpthread_ttid_3; //線程IDintt_arg; //給線程傳入的參數(shù)值//創(chuàng)建第一個(gè)線程t_arg=100;if(pthread_create(&tid,NULL,thread_func,&t_arg)) //創(chuàng)建線程,每次創(chuàng)建時(shí),非全局變量t_arg獨(dú)立不同;若t_arg是在main()外定義的全局變量,則所有線程的t_arg相同

perror("Failtocreatethread");sleep(2); //睡眠1秒,等待線程執(zhí)行//創(chuàng)建第二個(gè)線程t_arg=200;if(pthread_create(&tid_2,NULL,thread_func,&t_arg)) perror("Failtocreatethread");sleep(2);//創(chuàng)建第三個(gè)線程t_arg=300;if(pthread_create(&tid_3,NULL,thread_func,&t_arg))perror("Failtocreatethread");sleep(2);while(1){printf("Mainthread!\n");}return0;}49編譯過程要注意問題undefinedreferenceto'pthread_create'

undefinedreferenceto'pthread_join'

問題原因:

pthread庫不是Linux系統(tǒng)默認(rèn)的庫,連接時(shí)需要使用靜態(tài)庫libpthread.a,所以在使用pthread_create()創(chuàng)建線程,以及調(diào)用pthread_atfork()函數(shù)建立fork處理程序時(shí),需要鏈接該庫。

問題解決:

在編譯中要加-lpthread參數(shù)

gccthread.c-othread-lpthread

504取消線程線程的退出有幾種條件,當(dāng)線程本身的代碼運(yùn)行結(jié)束后,會(huì)自動(dòng)退出;或者線程代碼中調(diào)用return也會(huì)導(dǎo)致線程退出;還有一種情況是通過其他的線程把一個(gè)線程退出,pthread庫提供pthread_cancel()函數(shù)用來取消一個(gè)線程的執(zhí)行。函數(shù)定義如下:

#include<pthread.h> intpthread_cancel(pthread_tthread);514取消線程#include<pthread.h>#include<stdio.h>#include<stdlib.h>void*thread_func(void*arg) //線程函數(shù){int*val=arg;printf("Hi,I'mathread!\n");if(NULL!=arg){ //如果參數(shù)不為空,打印參數(shù)內(nèi)容while(1)printf("argumentset:%d\n",*val);}}intmain(){pthread_ttid; //線程IDintt_arg=100; //給線程傳入的參數(shù)值if(pthread_create(&tid,NULL,thread_func,&t_arg)) //創(chuàng)建線程perror("Failtocreatethread");sleep(1); //睡眠1秒,等待線程執(zhí)行printf("Mainthread!\n");If(tid!=NULL)pthread_cancel(tid); //取消線程return0;}525等待線程在線程操作實(shí)例中,主線程使用sleep()函數(shù)暫停自己的運(yùn)行,等待新創(chuàng)建的線程結(jié)束。使用延遲函數(shù)的方法在簡單的程序中還能對(duì)付,但是復(fù)雜一點(diǎn)的程序就不好用了。由于線程的運(yùn)行時(shí)間不確定,導(dǎo)致程序的運(yùn)行結(jié)果無法預(yù)測(cè)。pthread庫提供了一種等待其他線程結(jié)束的方法,使用pthread_join()函數(shù)等待一個(gè)線程結(jié)函數(shù)定義如下: #include<pthread.h> intpthread_join(pthread_tthread,void**value_ptr);value_ptr:退出進(jìn)程的返回值,若被等待進(jìn)程成功返回,函數(shù)返回0,一般取為NULL536使用pthread庫線程操作實(shí)例//pthread_demo.c#include<pthread.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>void*mid_thread(void*arg); //mid線程聲明void*term_thread(void*arg); //term線程聲明intmain(){pthread_tmid_tid,term_tid; //存放線程idif(pthread_create(&mid_tid,NULL,mid_thread,NULL)){ //創(chuàng)建mid線程perror("Createmidthreaderror!");return0;}if(pthread_create(&term_tid,NULL,term_thread,(void*)&mid_thread)){//創(chuàng)建term線程perror("Createtermthreadfail!\n");return0;}if(pthread_join(mid_tid,NULL)){ //等待mid線程結(jié)束perror("waitmidthreaderror!");return0;}if(pthread_join(term_tid,NULL)){ //等待term線程結(jié)束perror("waittermthreaderror!");return0;}return0;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(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ǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論