Linux環(huán)境下C程序設(shè)計第六章-進程控制_第1頁
Linux環(huán)境下C程序設(shè)計第六章-進程控制_第2頁
Linux環(huán)境下C程序設(shè)計第六章-進程控制_第3頁
Linux環(huán)境下C程序設(shè)計第六章-進程控制_第4頁
Linux環(huán)境下C程序設(shè)計第六章-進程控制_第5頁
已閱讀5頁,還剩165頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

內(nèi)容提要9:401/267第六章進程控制6.1進程概述6.2進程操作6.2.1進程創(chuàng)建6.2.2進程等待6.2.3進程的終止6.2.4

system函數(shù)6.2.5進程的同步?第六章進程控制9:402/267

本章首先介紹Linux下進程控制的相關(guān)內(nèi)容;然后介紹

Linux平臺下進程的操作,包括進程的創(chuàng)建、等待、終止、同步、system函數(shù)的操作;最后結(jié)合具體的項目案例,

闡述進程的相關(guān)操作的具體應(yīng)用。本節(jié)學(xué)習(xí)目標(biāo):√進程的創(chuàng)建√進程的等待√進程的終止√進程的同步√system函數(shù)6.1進程概述9:403/267

進程是操作系統(tǒng)中重要的概念。理解和掌握進程控制,是進行Linux下系統(tǒng)編程的關(guān)鍵。進程是具有一定功能的可并發(fā)執(zhí)行的程序在數(shù)據(jù)集合上的運行過程。進程和程序是與本質(zhì)的區(qū)別的。進程是動態(tài)的,是程序運行和資源分配的最小單位,包括進行的創(chuàng)建、運行、調(diào)度和消亡的整個過程;而程序是靜態(tài)的,是存儲在磁盤上的指令的集合,本身不擁有任何資源,只有用戶啟動該程序時候,它才啟動對應(yīng)的進程,程序才運行起來并占有相應(yīng)的系統(tǒng)資源。6.1進程概述9:404/267

在用戶看來,Linux是多任務(wù)的操作系統(tǒng),在同一時間內(nèi)可以同時運行多個任務(wù);對系統(tǒng)而言,Linux的多任務(wù)并不是真正的在同時間內(nèi)可以并行多個任務(wù),而是虛假的多任務(wù)同時執(zhí)行。那么Linux是如何實現(xiàn)多任務(wù)的同時執(zhí)行呢?Linux操作系統(tǒng)用時間片的方式實現(xiàn)多任務(wù)的同時執(zhí)行,每個任務(wù)輪流的占用CPU的一個時間片,而每個

任務(wù)可以頻繁的得到時間片執(zhí)行各自的任務(wù),由于單個時間片和宏觀上的時間相比很小,每個任務(wù)占用的時間片都很短,對用戶而言感覺不到多個任務(wù)的頻繁切換,如同多個任務(wù)同時在運行的情況。6.1進程概述9:405/267

一般而言,一個進程執(zhí)行一個獨立的任務(wù),也可以執(zhí)行多個任務(wù)。有時候,為了提高程序執(zhí)行的效率,一個任務(wù)可以被多個進程同時執(zhí)行,并發(fā)運行執(zhí)行任務(wù),這就是并發(fā)程序。執(zhí)行并發(fā)程序的多個進程需同步運行,進程之間相互獨立,也可以進行進程間的通信,比如不同進程使用相同的資源時候,會發(fā)生資源使用沖突。各個進程也需要相互合作,比如一個進程需要等待另一個進程運行出結(jié)果后,才會繼續(xù)運行。6.1進程概述9:406/267

在Linux操作系統(tǒng)中,進程被稱為進程控制塊(ProcessControl

Block,簡稱PCB)。進程控制塊PCB中包括了進程的描述信息、控制信息、資源信息等,這些信息供系統(tǒng)調(diào)用和進程執(zhí)行中自身使用,比如進程的ID,被稱作進程標(biāo)識符,是進程的身份證號碼,在系統(tǒng)中進程ID唯一地標(biāo)志一個進程,不會重復(fù)。多個進程可以合起來組成進程組,這樣就可以對進程批量操作,例如向進程組發(fā)送信號就可以實現(xiàn)向每個進程發(fā)送信號的功能。進程在運行過程中可以根據(jù)需要動態(tài)的產(chǎn)生子進程和結(jié)束進程。6.1進程概述9:407/267

用戶啟動程序后,系統(tǒng)就會啟動相應(yīng)的進程運行,進程在運行的過程中會處于不同的狀態(tài):運行狀態(tài)、等待調(diào)用和睡眠狀態(tài)。運行狀態(tài)是指進程占有CPU,正在執(zhí)行進程中;等待調(diào)用狀態(tài)是指進程正在等待獲得CPU;睡眠狀態(tài)是指進程等待某個事件發(fā)生,當(dāng)前不會處理任何事情。6.1進程概述9:408/267

多個程序被用戶啟動后,會啟動多個進程來完成對應(yīng)的任務(wù)。多個進程同時運行過程中會搶占資源和按照任務(wù)邏輯順序地執(zhí)行,這就要求進程間通信的同步和處理好沖突問題。解決進程間通信同步和沖突的方法有管道、信號量、共享內(nèi)存和消息隊列等。

進程運行過程都要占用一定的內(nèi)存區(qū)域,此區(qū)域用于保存進程運行過程中所用的變量和程序代碼。進程運行過程中具有獨立性,所以當(dāng)一個進程運行中出現(xiàn)錯誤時,不會影響到另外其他進程的運行過程,同時改變一個進程中的內(nèi)存中的數(shù)據(jù),只會影響本進程的內(nèi)部狀態(tài),不會對其他進程產(chǎn)生不良影響,這也是Linux系統(tǒng)穩(wěn)定性的重要原因。6.2進程操作9:409/267

在Linux系統(tǒng)中,進程操作主要是指通過系統(tǒng)函數(shù)和庫函數(shù)的調(diào)用,對進程進行創(chuàng)建、等待、終止和同步等操作,下面給出具體介紹。6.2.1進程創(chuàng)建9:4010/267

在Linux系統(tǒng)中,創(chuàng)建進程的方式有兩種:操作系統(tǒng)創(chuàng)建和父進程創(chuàng)建。操作系統(tǒng)創(chuàng)建的進程是平等關(guān)系,相互

間不存在繼承關(guān)系;父進程創(chuàng)建的子進程不是平等關(guān)系,相互間存在資源繼承關(guān)系。父進程創(chuàng)建的子進程,又可

以創(chuàng)建子進程,從而形成一個進程家族,子進程繼承了

父進程的所有資源,這類進程通常稱為用戶進程;在系

統(tǒng)啟動時,Linux操作系統(tǒng)會創(chuàng)建一些管理和分配系統(tǒng)資源的進程,這類進程稱為系統(tǒng)進程。1創(chuàng)建進程函數(shù)fork9:4011/267

系統(tǒng)創(chuàng)建進程的通用方法是使用函數(shù)fork,系統(tǒng)通過調(diào)用它來完成進程的創(chuàng)建工作。在Linux系統(tǒng)終端中使用幫助命令“man

fork”,得到函數(shù)的信息如下:#include

<unistd.h>pid_t

fork(void);1創(chuàng)建進程函數(shù)fork9:4012/267

該函數(shù)的返回類型為整型,用于創(chuàng)建一個新進程。創(chuàng)建進程后,若是父子進程會爭奪CPU,先搶到者先執(zhí)行,

另外一個進程掛起等待;若是需要父進程等待子進程執(zhí)

行完畢后繼續(xù)執(zhí)行,則需要在執(zhí)行fork操作后調(diào)用wait或waitpid,這樣父子進程會同時執(zhí)行程序。多個進程執(zhí)行同一個程序效果不大,所以子進程在fork后通過調(diào)用exec函數(shù)執(zhí)行其它程序。若不是父子進程,而是操作系統(tǒng)創(chuàng)

建的進程,那么進程之間的關(guān)系式平等關(guān)系。

若在父進程中函數(shù)成功調(diào)用后返回子進程的ID號;若在

子進程中函數(shù)成功調(diào)用后返回0;否則調(diào)用失敗則返回-1。2創(chuàng)建進程函數(shù)vfork9:4013/267

系統(tǒng)創(chuàng)建進程的另一個方法是使用函數(shù)vfork,系統(tǒng)通過調(diào)用它來完成進程的創(chuàng)建工作。在Linux系統(tǒng)終端中使用幫助命令“man

vfork”,得到函數(shù)的信息如下:#include

<unistd.h>#include

<sys/types.h>pid_t

vfork(void);2創(chuàng)建進程函數(shù)vfork9:4014/267該函數(shù)的返回類型為整型,也是用于創(chuàng)建一個新進程。與fork相比,vfork函數(shù)的功能和參數(shù)說明和fork函數(shù)類似,但也有自己的獨特之處,主要有兩點不同:第一,fork方

法創(chuàng)建的子進程,是父進程的完全拷貝,這樣的子進程獨立父進程,有良好的并發(fā)性能;而vfork方法創(chuàng)建的子進程,不是父進程的完全拷貝,而是和父進程共享地址空間,子進程需要完全運行在父進程的地址空間上,子進程對地址空間的數(shù)據(jù)修改同樣會影響到父進程。2創(chuàng)建進程函數(shù)vfork9:4015/267

第二,vfork方法創(chuàng)建的子進程會優(yōu)先運行,當(dāng)它執(zhí)行完

exit之后或調(diào)用exec后,父進程才可以運行;而fork方法創(chuàng)建的子進程是否優(yōu)先運行,取決于系統(tǒng)的調(diào)度算法。

基于這兩點不同,可以看出vfork方法不會拷貝父進程的地址空間,會節(jié)省系統(tǒng)的大量開銷,運行速度也會很快。3綜合示例9:4016/267

在本節(jié)最后,通過利用fork和vfork函數(shù)進行系統(tǒng)調(diào)用,來演示如何創(chuàng)建一個新進程,加強對進程控制的理解。如fork創(chuàng)建進程的范例6-1和vfork創(chuàng)建進程的范例6-2所示。例6-1

my_fork.c/****my_fork.c***/例6-2

my_vfork.c/****my_vfork.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼6.2.2進程等待9:4017/267

在Linux系統(tǒng)中,當(dāng)有多個進程同時運行時,進程間需要協(xié)作工作,可能用到進程等待的操作。進程間的等待包括父子進程間的等待和進程組內(nèi)成員間的等待。1進程等待9:4018/267

進程等待有兩種方法:wait和waitpid。,系統(tǒng)通過調(diào)用它們來完成進程的等待工作。在Linux系統(tǒng)終端中使用幫助命令“man

wait”,得到函數(shù)的信息如下:#include

<sys/types.h>#include

<sys/wait.h>pid_t

wait(int

*status);pid_t

waitpid(pid_t

pid,

int

*status,

int

options);1進程等待9:4019/267

wait:該函數(shù)的返回類型為整型,專用于等待子進程。

status參數(shù)是個整型的指針,用于存放子進程的結(jié)束狀態(tài)。當(dāng)wait被調(diào)用后,父進程被掛起,直到子進程結(jié)束后返回。若wait調(diào)用的父進程沒有子進程,返回失敗。調(diào)用成功時,返回等待狀態(tài)進程的ID號;調(diào)用失敗時,返回為-1。1進程等待9:4020/267

waitpid:該函數(shù)的返回類型為整型,調(diào)用更靈活,用來等待指定的進程。status參數(shù)是個整型的指針,用于存放子進程的結(jié)束狀態(tài)。pid參數(shù)是個整型參數(shù),用于指定所等待的進程,pid大于零表示等待進程id為pid所指定值的子進程;pid等于零表示等待進程組id等于發(fā)出調(diào)用進程的進程組id的子進程;pid等于-1表示等待所有子進程,等價于wait調(diào)用;pid小于-1表示等待進程組id為pid的絕對值的子進程。options參數(shù)是個整型參數(shù),用于指定進程所做的操作,取值為0表示進程掛起等待結(jié)束;取值為

WNOHANG表示不使進程掛起而即刻返回;取值為

WUNTRACED表示進程已經(jīng)結(jié)束并返回。調(diào)用成功時,返回等待狀態(tài)進程的ID號;調(diào)用失敗時,返回為-1。2綜合示例9:4021/267

在本節(jié)最后,通過利用wait和waitpid函數(shù)進行系統(tǒng)調(diào)用,來演示如何等待一個進程,加強對進程控制的理解。如wait和waitpid進程等待的范例6-3所示。例6-3

my_wait.c/****my_wait.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼6.2.3進程終止9:4022/267

在Linux系統(tǒng)中,進程的終止表示進程退出運行。進程的退出方法有正常退出和異常退出兩種。不管是何種方式終止進程,最終都會執(zhí)行內(nèi)核中用于關(guān)閉該進程打開的文件描述符并釋放系統(tǒng)資源的同一段代碼。1進程正常終止9:4023/267

進程正常終止的方法包括執(zhí)行exit函數(shù)、_exit函數(shù)和在主函數(shù)中執(zhí)行return。系統(tǒng)通過調(diào)用它們來完成進程的正常終止工作。在Linux系統(tǒng)終端中使用幫助命令“man

3exit”和“man

2

exit”,得到函數(shù)的信息如下:#include

<stdlib.h>void

exit(int

status);#include

<unistd.h>void

_exit(int

status);1進程正常終止9:4024/267

exit:該函數(shù)的返回類型為空,用于正常終止進程。status參數(shù)是個整型參數(shù),用于存放進程的退出狀態(tài)。

_exit:該函數(shù)和exit函數(shù)的功能和參數(shù)類似,其區(qū)別有兩點:第一,exit和_exit函數(shù)的頭文件聲明位置不同,分別為頭文件stdlib.h和unistd.h中;第二,exit函數(shù)執(zhí)行完相關(guān)操作后將控制權(quán)返回給內(nèi)核,而_exit函數(shù)執(zhí)行完操作

后將控制權(quán)即刻交給內(nèi)核。

return:該語句執(zhí)行完后正常退出進程,它和exit、_exit兩個函數(shù)的區(qū)別有兩點:第一,exit和_exit二者都是函數(shù),帶有參數(shù),而return函數(shù)體中執(zhí)行完后的一個返回語句;

第二,exit和_exit函數(shù)執(zhí)行完相關(guān)操作后將控制權(quán)交給內(nèi)

核,而return將控制權(quán)返回給調(diào)用者。2進程異常終止9:4025/267

進程異常終止的方法包括執(zhí)行abort函數(shù)和進程收到結(jié)束信號如SIGABRT等。系統(tǒng)通過調(diào)用它們來完成進程的異

常終止工作。在Linux系統(tǒng)終端中使用幫助命令“manabort”,得到函數(shù)的信息如下:#include

<stdlib.h>void

abort(void);2進程異常終止9:4026/267

abort:該函數(shù)的返回類型為空,用于異常終止進程。

abort函數(shù)和exit和_exit函數(shù)的區(qū)別是:abort異常終止進程,進程的文件描述符沒有關(guān)閉和占用的資源沒有釋放;

exit和_exit函數(shù)正常終止進程,進程的文件描述符正常關(guān)閉和占用的資源正常釋放。

進程異常終止會出現(xiàn)僵死進程。僵死進程是這樣產(chǎn)生的:父進程fork子進程后,沒有調(diào)用wait或waitpid函數(shù)等待子進程的結(jié)束,而子進程運行完后又先于父進程提前終止,如此,子進程就進入僵死狀態(tài)。僵死進程會一直占用系

統(tǒng)資源,并且一直保持下去,造成資源浪費。3綜合示例9:4027/267

在本節(jié)最后,通過利用正常和異常終止進程函數(shù)進行系統(tǒng)調(diào)用,來演示如何終止一個進程,加強對進程控制的理解。如正常和異常終止進程函數(shù)的范例6-

4所示。例6-4

my_

exit_abort.c/****my_exit_abort.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼6.2.4

system函數(shù)9:4028/267

在Linux系統(tǒng)編程中,可以使用system函數(shù)執(zhí)行fork、exec和wait等各種系統(tǒng)命令,完成進程相關(guān)的操作。

system函數(shù)是和Linux操作系統(tǒng)緊密相關(guān)的函數(shù),用戶根據(jù)自身需要,在程序中方便的使用此函數(shù)實現(xiàn)進程操作相關(guān)的功能。1

system函數(shù)9:4029/267

執(zhí)行系統(tǒng)的命令行完成進程操作的系統(tǒng)函數(shù)是system函數(shù)。系統(tǒng)通過調(diào)用它在程序中完成進程操作的相關(guān)工作。在Linux系統(tǒng)終端中使用幫助命令“man

system”,得到函數(shù)的信息如下:#include

<stdlib.h>int

system(const

char

*command);1

system函數(shù)9:4030/267

system:該函數(shù)的返回類型為整型,用于執(zhí)行系統(tǒng)的命令。command參數(shù)是一個字符串指針,指向表示命令行的字符串。command參數(shù)值可以為NULL,可用于測試

system函數(shù)是否有效,若返回值為非空指針,表示其有效;若返回值為0,表示其無效。command參數(shù)值也可

以為fork、exec和waitpid等相關(guān)的命令行,在執(zhí)行system函數(shù)的過程中,其返回值是復(fù)雜多變的,調(diào)用fork、exec和waitpid任意一個命令行失敗將會導(dǎo)致system函數(shù)

的執(zhí)行失敗。若調(diào)用exec失敗,表示無法執(zhí)行所設(shè)命令,將返回shell操作的返回值;若調(diào)用waitpid失敗,表示等待失敗,將返回-1;若調(diào)用fork失敗,表示創(chuàng)建進程失敗,將返回-1。2綜合示例9:4031/267

在本節(jié)最后,通過利用system函數(shù)進行系統(tǒng)調(diào)用,來演示如何使用system函數(shù)執(zhí)行命令行參數(shù),加強對進程控制的理解。system函數(shù)如范例6-5所示。例6-5

my_

system.c/****my_system.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼6.2.5進程同步9:4032/267

Linux系統(tǒng)是多任務(wù)的操作系統(tǒng),用戶可以同時運行多個進程執(zhí)行多個任務(wù),形成并發(fā)程序和并發(fā)進程,而且多個進程間通常不是相互獨立的,有時它們需要保持多個進程間的相互配合進行同步工作。因此,對多任務(wù)多進程的系統(tǒng)而言,如何協(xié)調(diào)不同進程間的同步運行,處理好它們之間的關(guān)系是十分重要的環(huán)節(jié)。6.2.5進程同步9:4033/267

進程同步的實例很多,例如,多個進程需要訪問同一個設(shè)備或調(diào)用同一個程序。多個進程訪問同一程序示例:

網(wǎng)絡(luò)上不同終端和不同的售票窗口,會調(diào)用同一段售票

程序代碼出售同一車次的火車票,如果不同的終端和售

票窗口同時調(diào)用同一段售票程序代碼出售火車票,那么

它們所讀取的余票信息是一樣的,就會賣出相同的車票,進而產(chǎn)生沖突問題,這就需要對不同的終端和售票窗口

調(diào)用的同一段售票程序代碼,進行加鎖,實現(xiàn)同一時間

內(nèi)只有一個進程終端調(diào)用,也就是說需要實現(xiàn)進程間的

同步。多個進程訪問同一設(shè)備的示例:當(dāng)有多個進程同

時對同一設(shè)備打印機進行打印操作時,會造成打印的數(shù)

據(jù)混亂,這也需要協(xié)調(diào)不同進程對打印機設(shè)備的訪問的

同步。6.2.5進程同步9:4034/267

實現(xiàn)進程間同步的方法包括文件鎖定、信號量、管道、消息、套接字和共享內(nèi)存等。其中管道、消息、套接字和共享內(nèi)存不僅用于進程間的通信,也可用于進程間的同步;文件鎖和信號量是用于進程間的同步的。這部分內(nèi)容將在第八章中詳細(xì)介紹,在此簡單介紹進程間的同步關(guān)系。

實現(xiàn)進程間同步也會存在很多問題包括死鎖,訪問設(shè)備沖突等,這部分內(nèi)容將在第八章中詳細(xì)介紹,在此只是簡單介紹進程間的同步關(guān)系。6.4本章小結(jié)9:4035/267

進程的相關(guān)操作是Linux系統(tǒng)編程的重要環(huán)節(jié)。熟悉進程控制的API的調(diào)用,對于Linux平臺下的操作系統(tǒng)編程將大有幫助。本章介紹了進程操作的理論知識,然后結(jié)合具體的案例,詳細(xì)闡述了進程的創(chuàng)建、等待、終止、同步、system函數(shù)的操作,加深了理論和實踐的結(jié)合度,達到了學(xué)以致用的目的。6.5本章習(xí)題9:4036/2676.5本章習(xí)題9:4037/2676.5本章習(xí)題9:4038/267內(nèi)容提要第七章線程控制7.1線程控制7.1.1線程的創(chuàng)建7.1.2線程的終止7.1.3線程的同步7.1.4私有數(shù)據(jù)7.3本章小結(jié)9:4039/267第七章線程控制9:4040/267

本章首先介紹Linux下線程控制的相關(guān)內(nèi)容;然后介紹

Linux平臺下線程的操作,包括線程的創(chuàng)建、終止、同步、私有數(shù)據(jù)的操作;最后結(jié)合具體示例,闡述線程的相關(guān)

操作的具體應(yīng)用。本節(jié)學(xué)習(xí)目標(biāo):√線程的創(chuàng)建√線程的終止√線程的同步√私有數(shù)據(jù)7.1線程控制9:4041/267

本節(jié)介紹線程的相關(guān)知識。在Linux操作系統(tǒng)中,進程和線程是緊密相關(guān)的,又相互有區(qū)別的。在操作系統(tǒng)中,

進程是資源分配的最小單位,而線程是任務(wù)獨立運行的

最小單位。Linux操作系統(tǒng)是支持多任務(wù)多進程的,同時在同一進程內(nèi)也支持多線程的,這是為什么呢?這是因

為多線程較多進程而言,不僅節(jié)約資源,而且節(jié)約時間,這對操作系統(tǒng)的設(shè)計和運行非常重要和關(guān)鍵,具體表現(xiàn)

在如下幾個方面。7.1線程控制9:4042/267

首先,創(chuàng)建新線程花費較少的時間,而且占用的系統(tǒng)資源也要少的多。在Linux系統(tǒng)中,每個進程都有各自獨立的地址空間,而在同一進程內(nèi)的多個線程是共享該進程的地址空間的,所以創(chuàng)建一個新進程要耗費較多時間為其分配系統(tǒng)資源,供其正常運轉(zhuǎn),而線程較少。

其次,線程間切換的速度要遠快于進程間的切換速度。具體原因是在系統(tǒng)調(diào)度過程中,線程共享地址空間而進程地址空間相互獨立。7.1線程控制9:4043/267

第三,線程間的通信省時且方便。進程間的地址空間是相互獨立的,彼此通信必須經(jīng)過操作系統(tǒng)進行專門的通

信方式進行通信;而進程內(nèi)的多個線程間地址空間共享,彼此通信不必經(jīng)過操作系統(tǒng),線程間的數(shù)據(jù)相互可以看

到。

再次,線程提高程序的響應(yīng)速度。在多任務(wù)的Linux操作系統(tǒng)中,有很多非常耗時的操作,比如從網(wǎng)絡(luò)下載很大

的圖片,它會導(dǎo)致用戶一直處于等待狀態(tài)而不能進行其

他操作,多線程環(huán)境下可以將這個耗時的操作交給一個

單獨的線程來完成,讓用戶不用等待可以進行其他工作,提高程序的響應(yīng)速度。7.1線程控制9:4044/267

最后,多線程提高CPU的處理效率,發(fā)揮硬件的全部潛力?,F(xiàn)代計算機都采用多核技術(shù),如果采用多個線程在不同的處理器上同時運行,可以較大提高程序的運行效率和速度。

鑒于線程有這么多的優(yōu)點,所以下面將從線程的創(chuàng)建、終止、同步和私有數(shù)據(jù)四個方面給出線程的具體介紹。7.1.1線程創(chuàng)建9:4045/267

在Linux系統(tǒng)編程中,可以使用pthread_create函數(shù)完成線程創(chuàng)建的相關(guān)工作。pthread_create函數(shù)是和Linux操作系統(tǒng)緊密相關(guān)的函數(shù),用戶根據(jù)自身需要,在程序中方便的使用此函數(shù)實現(xiàn)線程操作相關(guān)的功能。前面所介紹的示例都是按照固定順序執(zhí)行的單線程程序,若是在主線程中創(chuàng)建新的線程,就會同時運行兩個程序,提高程序執(zhí)行的效率。1線程創(chuàng)建函數(shù)9:4046/267

執(zhí)行線程創(chuàng)建函數(shù)是pthread_create函數(shù)。系統(tǒng)通過調(diào)用它在程序中完成線程創(chuàng)建的相關(guān)工作。在Linux系統(tǒng)終端中使用幫助命令“man

pthread_create”,得到函數(shù)的

信息如下:#include

<pthread.h>

int

pthread_create(pthread_t

*thread,

constpthread_attr_t

*attr,void

*(*start_routine)

(void

*),

void

*arg);1線程創(chuàng)建函數(shù)9:4047/267

該函數(shù)的返回類型為整型,用于執(zhí)行線程的創(chuàng)建。thread參數(shù)是一個指針,指向成功創(chuàng)建線程后所返回的線程ID號。attr參數(shù)是一個指向pthread_attr_t的結(jié)構(gòu)體指針,使用該結(jié)構(gòu)體指定所創(chuàng)建線程的各種屬性,若attr參數(shù)值為NULL,表示使用默認(rèn)屬性。start_routine參數(shù)是一個函數(shù)指針,用于指向線程創(chuàng)建成功后所要調(diào)用并執(zhí)行的函數(shù),此函數(shù)也稱為線程函數(shù)。arg參數(shù)是一個指針,指向線程函數(shù)的參數(shù)。

若線程創(chuàng)建成功,則pthread_create函數(shù)返回0;否則創(chuàng)建失敗返回非0。成功創(chuàng)建線程后,新線程開始運行線程函數(shù),原調(diào)用線程繼續(xù)運行。2線程創(chuàng)建相關(guān)函數(shù)9:4048/267

在線程創(chuàng)建成功后,還要調(diào)用線程創(chuàng)建相關(guān)的一些函數(shù),比如獲取本線程ID的函數(shù)、判斷兩個線程ID是否指向同

一個線程的函數(shù)、用來保證線程函數(shù)在進程中僅執(zhí)行一

次的函數(shù)等,這些函數(shù)可以輔助新創(chuàng)建的線程做一些有

益的功能,下面給出它們的函數(shù)聲明。2線程創(chuàng)建相關(guān)函數(shù)9:4049/267

在Linux系統(tǒng)終端中使用幫助命令“man

pthread_once”、

“man

pthread_self”和“man

pthread_equal”,得到

函數(shù)的信息如下:#include

<pthread.h>

int

pthread_once(pthread_once_t

*once_control,void(*init_routine)(void));pthread_once_t

once_control

=

PTHREAD_ONCE_INIT;#include

<pthread.h>pthread_t

pthread_self(void);#include

<pthread.h>int

pthread_equal(pthread_t

t1,

pthread_t

t2);2線程創(chuàng)建相關(guān)函數(shù)9:4050/267

pthread_once:該函數(shù)的返回類型為整型,用來保證線程函數(shù)在進程中僅執(zhí)行一次。once_control參數(shù)是一個指針,指向pthread_once_t結(jié)構(gòu)體。init_routine參數(shù)是一個函數(shù)指針,用來指向一次執(zhí)行的函數(shù)。若函數(shù)執(zhí)行成功,則返回0;否則返回非0。

pthread_self:該函數(shù)的返回類型為整型,用來獲取本線程ID號。若函數(shù)執(zhí)行成功,則返回本線程ID號;否則返

回0。

pthread_equal:該函數(shù)的返回類型為整型,用來判斷兩個線程ID是否指向同一個線程。t1是線程1的ID號,t2是線程2的ID號。若函數(shù)執(zhí)行成功,則返回非0;否則返回

0。3綜合示例9:4051/267

在本節(jié)最后,通過利用線程創(chuàng)建函數(shù)進行系統(tǒng)調(diào)用,來演示如何創(chuàng)建線程,加強對線程控制的理解。pthread_create函數(shù)如范例7-1所示。例7-1

my_

createthread.c/****my_createthread.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼7.1.2線程終止9:4052/267

在Linux系統(tǒng)編程中,線程的終止方式有兩種:一種是使用return語句從線程函數(shù)中返回;另一種是調(diào)用

phtread_exit函數(shù)退出線程。用戶根據(jù)自身需要,在程序中方便的使用這兩種方式結(jié)束線程。

線程終止時,一般是從主線程中退出,從而結(jié)束整個進程。若是在主線程中,調(diào)用了exit函數(shù)或通過return語句返回,則整個進程中所有的線程終止,進程終止;若是

在主線程中調(diào)用了pthread_exit函數(shù),則進程不會結(jié)束,只是主線程結(jié)束,進程內(nèi)的其它線程仍可以正常運行;

若是從子線程中調(diào)用了exit函數(shù)或通過return語句返回,則子線程消亡,主線程和進程內(nèi)的其它線程不受影響。7.1.2線程終止9:4053/267

線程終止的核心問題是釋放資源的問題。如果一個線程終止后沒有及時釋放所持有的資源,則此資源會被認(rèn)為被其一直獨占,造成永遠無法釋放,會導(dǎo)致其它線程或進程無法獲得該資源,而一直處于無限的等待狀態(tài),這就是所謂的死鎖。所以線程終止時,要及時釋放所占有的各種資源,使其它進程獲得資源及時運行。

線程終止的另一個關(guān)鍵問題是線程間的同步問題。在

Linux系統(tǒng)中,運行在進程中的各個線程是相互獨立的,某個線程的終止不會影響到別的線程,并且終止的線程

也不會及時的把占用的資源歸還給系統(tǒng),而是仍歸其所

在的進程擁有。線程之間可以使用pthread_join函數(shù)調(diào)用來通知或等待其它線程的結(jié)束。1線程終止函數(shù)9:4054/267

執(zhí)行線程終止函數(shù)是pthread_exit函數(shù)。系統(tǒng)通過調(diào)用它在程序中完成線程終止的相關(guān)工作。在Linux系統(tǒng)終端中使用幫助命令“man

pthread_exit”,得到函數(shù)的信息如下:#include

<pthread.h>void

pthread_exit(void

*retval);

該函數(shù)的返回類型為空,用于完成線程的終止。retval參數(shù)是一個指針,指向本線程所設(shè)置的變量值,并返回給

調(diào)用線程。2等待線程結(jié)束函數(shù)9:4055/267

等待線程結(jié)束的函數(shù)是pthread_

join函數(shù)。系統(tǒng)通過調(diào)用它在程序中完成等待線程結(jié)束的相關(guān)工作。在Linux系統(tǒng)終端中使用幫助命令“man

pthread_join”,得到函數(shù)的信息如下:#include

<pthread.h>int

pthread_join(pthread_t

thread,

void

**retval);2等待線程結(jié)束函數(shù)9:4056/267

該函數(shù)的返回類型為空,用于等待一個線程的結(jié)束。

thread參數(shù)是整型參數(shù),表示等待線程的ID號。retval參數(shù)是個二級指針型參數(shù),用于指向等待線程所返回變量的指針。該函數(shù)的調(diào)用者將被掛起并等待thread線程終止,并且等待線程只允許一個調(diào)用線程使用pthread_join函數(shù)

等待它的結(jié)束;若是被多個調(diào)用線程等待,除了第一個收到信號的線程返回成功外,其它調(diào)用線程均返回錯誤。3綜合示例9:4057/267

在本節(jié)最后,通過利用線程終止函數(shù)進行系統(tǒng)調(diào)用,來演示如何終止線程,加強對線程控制的理解。pthread_exit函數(shù)如范例7-2所示。例7-2

my_

threadexit_join.c/****my_threadexit_join.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼7.1.3線程同步9:4058/267

在Linux系統(tǒng)編程中,多線程最核心的問題是資源共享中的同步問題。如果一個線程終止后沒有及時釋放所持有的資源,則此資源會被認(rèn)為被其一直獨占,造成永遠無法釋放,會導(dǎo)致其它線程永遠無法獲得該資源,而一直處于無限的等待狀態(tài),這就是所謂的死鎖。所以如何解決線程間的同步問題,是實現(xiàn)多線程編程的關(guān)鍵問題。7.1.3線程同步9:4059/267

多線程編程的另一個關(guān)鍵問題是線程間的同步問題。在

Linux系統(tǒng)中,運行在進程中的各個線程是相互獨立的,某個線程的終止不會影響到別的線程,并且終止的線程也不會及時的把占用的臨界資源歸還給系統(tǒng),而是仍歸其所在的進程擁有,導(dǎo)致進程內(nèi)的其它線程沒有及時收到通知消息,不能使用臨界資源,不能實現(xiàn)彼此線程間的同步協(xié)調(diào)運行。

鑒于上述問題,Linux系統(tǒng)提供了多種方式處理線程間同步問題,目前最常用的同步技術(shù)包括互斥鎖、條件變量。下面給出具體介紹。1互斥鎖9:4060/267

互斥鎖要求同一時刻只有一個線程訪問同一個設(shè)備或同一段代碼,通過訪問前加鎖和訪問后解鎖的機制來實現(xiàn)多線程間的同步問題。

支持線程同步的互斥鎖的函數(shù)有多個,包括初始化、加鎖、解鎖、注銷等互斥鎖函數(shù)。系統(tǒng)通過調(diào)用它們在程序中完成線程同步的相關(guān)工作。在Linux系統(tǒng)終端中使用幫助命令,得到互斥鎖的函數(shù)的信息如下:1互斥鎖9:4061/267#include

<pthread

.h>

int

pthread_mutex_init(pthread_mutex_t

*mutex,

constpthread_mutexattr_t

*mutexattr);int

pthread_mutex_lock(pthread_mutex_t

*mutex);int

pthread_mutex_trylock(pthread_mutex_t

*mutex);int

pthread_mutex_unlock(pthread_mutex_t

*mutex);int

pthread_mutex_destroy(pthread_mutex_t

*mutex);1互斥鎖9:4062/267

pthread_mutex_init:該函數(shù)的返回類型為整型,用于初始化一個互斥鎖。mutex參數(shù)是一個指針,指向生成的互斥鎖。mutexattr參數(shù)是一個指針,互斥鎖的屬性,若它為NULL則表示采用系統(tǒng)默認(rèn)的屬性;若為普通鎖,則表

示當(dāng)線程加鎖后,其余申請加鎖的線程形成等待隊列,

解鎖后按照優(yōu)先級獲得鎖;若為適應(yīng)鎖,則表示解鎖后

重新競爭;若為檢錯鎖,則表示當(dāng)相同線程請求同一個

鎖時,返回EDEADLK,否則執(zhí)行的動作與普通鎖一樣;若為嵌套鎖,則表示允許同一個線程對同一個鎖多次加鎖,通過多次unlock解鎖,若不是同線程請求則在解鎖后重新競爭。1互斥鎖9:4063/267

pthread_mutex_lock:該函數(shù)的返回類型為整型,用于對一個線程加鎖,若不成功則阻塞等待。mutex參數(shù)含義同pthread_mutex_init函數(shù)中的相同。

pthread_mutex_trylock:該函數(shù)的返回類型為整型,用于對一個線程測試加鎖,若不成功則立即返回。mutex參數(shù)含義同pthread_mutex_init函數(shù)中的相同。1互斥鎖9:4064/267

pthread_mutex_unlock:該函數(shù)的返回類型為整型,用于對一個線程解鎖。mutex參數(shù)含義同

pthread_mutex_init函數(shù)中的相同。

pthread_mutex_destroy:該函數(shù)的返回類型為整型,用于注銷一個互斥鎖。mutex參數(shù)含義同

pthread_mutex_init函數(shù)中的相同。上述五個函數(shù)調(diào)用成功返回0,否則調(diào)用失敗返回錯誤碼。1互斥鎖9:4065/267

綜上所述,在Linux系統(tǒng)編程中,使用互斥鎖實現(xiàn)多線程的同步基本上需要四步來完成。首先,使用前必須對互

斥鎖進行初始化操作。初始化有靜態(tài)初始化和函數(shù)初始

化兩種方式,靜態(tài)初始化就是對互斥鎖直接賦值;函數(shù)

初始化就是通過調(diào)用pthread_mutex_init函數(shù)初始化互斥鎖。其次,調(diào)用pthread_mutex_lock或pthread_mutex_trylock函數(shù)對互斥鎖進行加鎖。然后,調(diào)用pthread_mutex_unlock函數(shù)對互斥鎖進行解鎖,解

鎖要求互斥鎖必須處于加鎖狀態(tài)和調(diào)用線程必須是加鎖

線程。最后,互斥鎖使用完后,調(diào)用

pthread_mutex_destroy函數(shù)對互斥鎖進行清除工作。2條件變量9:4066/267

條件變量是在互斥鎖的基礎(chǔ)上,通過使用線程間共享的全局變量,使用判斷語句判斷條件成立則執(zhí)行某地代碼,否則等待條件成立,來實現(xiàn)線程間的同步問題。

支持線程同步的條件變量函數(shù)有多個,包括初始化、等待、解除、清除等互斥鎖函數(shù)。系統(tǒng)通過調(diào)用它們在程序中完成線程同步的相關(guān)工作。在Linux系統(tǒng)終端中使用幫助命令,得到互斥鎖的函數(shù)的信息如下:2條件變量9:4067/267?#include

<pthread.h>

pthread_cond_t

cond

=PTHREAD_COND_INITIALIZER;

int

pthread_cond_init(pthread_cond_t

*restrict

cond,const

pthread_condattr_t

*restrict

attr);

int

pthread_cond_wait(pthread_cond_t

*restrictcond,pthread_mutex_t

*restrict

mutex);

int

pthread_cond_timedwait(pthread_cond_t

*restrictcond,pthread_mutex_t

*restrict

mutex,const

struct

timespec

*restrict

abstime);2條件變量9:4068/267int

pthread_cond_signal(pthread_cond_t

*cond);int

pthread_cond_broadcast(pthread_cond_t

*cond);int

pthread_cond_destroy(pthread_cond_t

*cond);2條件變量9:4069/267

pthread_cond_init:該函數(shù)的返回類型為整型,用于初始化條件變量。cond參數(shù)是一個指針,指向條件變量。

attr參數(shù)是一個指針,表示條件變量的屬性。

pthread_cond_wait:該函數(shù)的返回類型為整型,表示基

于條件變量阻塞并無條件等待。cond參數(shù)含義同

pthread_cond_init函數(shù)中的相同。mutex參數(shù)是一個指針,指向互斥鎖。

pthread_cond_timedwait:該函數(shù)的返回類型為整型,功能同pthread_cond_wait函數(shù)一樣,用于對條件變量的限時等待,超時后將無條件返回。cond參數(shù)和mutex參數(shù)

含義同pthread_cond_wait函數(shù)中的相同。abstime參數(shù)

表示等待的時間。2條件變量9:4070/267

pthread_cond_signal:該函數(shù)的返回類型為整型,用于解除特定線程的阻塞或從等待隊列中激活第一個入隊的線程。cond參數(shù)含義同pthread_cond_init函數(shù)中的相同。

pthread_cond_broadcast:該函數(shù)的返回類型為整型,用于解除所有線程的阻塞。cond參數(shù)含義同

pthread_cond_init函數(shù)中的相同。

pthread_cond_destroy:該函數(shù)的返回類型為整型,用于清除條件變量。cond參數(shù)含義同pthread_cond_init函數(shù)中的相同。上述六個函數(shù)調(diào)用成功返回0,否則調(diào)用失敗返回錯誤碼。2條件變量9:4071/267

綜上所述,在Linux系統(tǒng)編程中,使用條件變量實現(xiàn)多線程的同步基本上需要四步來完成。首先,使用前必須對

條件變量進行初始化操作。初始化有靜態(tài)初始化和函數(shù)

初始化兩種方式,靜態(tài)初始化就是對條件變量直接賦值;函數(shù)初始化就是通過調(diào)用pthread_cond_init函數(shù)初始化條件變量。其次,調(diào)用pthread_cond_wait或pthread_cond_timedwait函數(shù)對條件變量進行等待。然后,調(diào)用pthread_cond_signal或pthread_cond_broadcast函

數(shù)解除特定或所有線程的阻塞。最后,條件變量使用完后,調(diào)用pthread_cond_destroy函數(shù)對條件變量進行清除工作,只有在沒有等待線程等待該條件變量的時候,才可以清除它。3綜合示例9:4072/267

在本節(jié)最后,通過利用線程同步函數(shù)進行系統(tǒng)調(diào)用,來演示如何進行線程的同步,加強對線程控制的理解。pthread_mutex_cond函數(shù)如范例7-3所示。例7-3

my_pthread_mutex_cond.c/****my_pthread_mutex_cond.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼7.1.4私有數(shù)據(jù)9:4073/267

在Linux系統(tǒng)多線程的編程中,同一進程內(nèi)的各個線程可以共享進程的數(shù)據(jù)空間,包括全局變量,但是線程也需要保存自己的全局變量,而且又要求這種全局變量只供本線程所私有。例如標(biāo)準(zhǔn)的出錯代碼變量ERRNO,系統(tǒng)要求它是個全局變量,每個函數(shù)出錯后,都可以訪問到它,并且返回本線程所要求的出錯代碼值。這種為線程所私有的全局變量就是線程的私有數(shù)據(jù)(Thread-specific

Data簡稱TSD),它可以被本線程內(nèi)的各個函數(shù)訪問,但是其它線程函數(shù)無法訪問它的值。1線程私有數(shù)據(jù)函數(shù)9:4074/267

線程私有數(shù)據(jù)采樣了一鍵多值技術(shù)。進程內(nèi)的各個線程都可以通過公共的鍵名來訪問它的值,但是各個線程所訪問的值是不一樣的。

支持線程私有數(shù)據(jù)的函數(shù)有多個,包括創(chuàng)建、設(shè)置、讀取、刪除等函數(shù)。系統(tǒng)通過調(diào)用它們在程序中完成線程私有數(shù)據(jù)相關(guān)工作。在Linux系統(tǒng)終端中使用幫助命令,得到線程私有數(shù)據(jù)的函數(shù)信息如下:1線程私有數(shù)據(jù)函數(shù)9:4075/267#include

<pthread.h>

int

pthread_key_create(pthread_key_t

*key,

void(*destructor)(void*));int

pthread_setspecific(pthread_key_t

key,

const

void*value);void

*pthread_getspecific(pthread_key_t

key);int

pthread_key_delete(pthread_key_t

key);1線程私有數(shù)據(jù)函數(shù)9:4076/267

pthread_key_create:該函數(shù)的返回類型為整型,用于創(chuàng)建一個鍵。key參數(shù)是一個指針,指向生成的鍵值。

destructor參數(shù)是一個函數(shù)指針,指向線程退出時所要執(zhí)行的以key關(guān)聯(lián)的數(shù)據(jù)為參數(shù)的釋放資源的函數(shù)。key值創(chuàng)建成功后,進程內(nèi)的所有線程都可以訪問它,并且各

個線程可以往key中注入自己的值,實現(xiàn)一鍵多值的線程私有數(shù)據(jù)功能。函數(shù)調(diào)用成功返回0,否則調(diào)用失敗返回錯誤碼。1線程私有數(shù)據(jù)函數(shù)9:4077/267

pthread_setspecific:該函數(shù)的返回類型為整型,用于為一個鍵設(shè)置新線程的私有數(shù)據(jù)。key參數(shù)是一個類型為

pthread_key_t的參數(shù),表示具體的鍵名。value參數(shù)是一個指針,指向所設(shè)置鍵的具體值。函數(shù)調(diào)用成功返回0,否則調(diào)用失敗返回錯誤碼。

pthread_getspecific:該函數(shù)的返回類型為指針,用于從一個鍵中讀取本線程的私有數(shù)據(jù)。key參數(shù)含義同

pthread_setspecific函數(shù)中的相同。函數(shù)調(diào)用成功返回與

key關(guān)聯(lián)的值,否則調(diào)用失敗返回NULL。1線程私有數(shù)據(jù)函數(shù)9:4078/267

pthread_key_delete:該函數(shù)的返回類型為整型,用于刪除指定的鍵。key參數(shù)含義同pthread_setspecific函數(shù)中的相同。鍵刪除成功后,其所占用的內(nèi)存也被釋放。函

數(shù)調(diào)用成功返回0,否則調(diào)用失敗返回錯誤碼。

綜上所述,在Linux系統(tǒng)編程中,使用線程私有數(shù)據(jù)進行多線程編程基本上需要四步來完成。首先,使用前必須

通過調(diào)用pthread_key_create函數(shù)創(chuàng)建一個鍵。其次,調(diào)用pthread_setspecific函數(shù)為一個鍵設(shè)置新線程的私有數(shù)據(jù)。然后,調(diào)用pthread_getspecific函數(shù)從一個鍵中讀取本線程的私有數(shù)據(jù)。最后,私有數(shù)據(jù)使用完后,調(diào)用

pthread_key_delete函數(shù)刪除指定的鍵。2綜合示例9:4079/267

在本節(jié)最后,通過利用線程私有數(shù)據(jù)函數(shù)進行系統(tǒng)調(diào)用,來演示如何創(chuàng)建和使用線程的私有數(shù)據(jù),加強對線程控制的理解。pthread_key_value函如范例

7-4所示。例7-4

my_

pthread_key_value.c/****my_pthread_key_value.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼7.3本章小結(jié)9:4080/267

線程的相關(guān)操作是Linux編程的重要環(huán)節(jié)。熟悉線程控制的API的調(diào)用,對于

Linux平臺下的操作系統(tǒng)編程將大有幫助。本章介紹了線程操作的理論知識,然后結(jié)合具體的項目案例,詳細(xì)闡述了線程的創(chuàng)建、終止、同步、私有數(shù)據(jù)的操作,在具體的項目案例中的具體應(yīng)用,加深了理論和實踐的結(jié)合度,達到了學(xué)以致用的目的。7.4本章習(xí)題9:4081/2677.4本章習(xí)題9:4082/2677.4本章習(xí)題9:4083/267內(nèi)容提要9:4084/267第八章進程間通信8.1概述8.2共享內(nèi)存8.3信號量8.4管道通信8.4.1管道的創(chuàng)建和關(guān)閉8.4.2管道的讀寫操作8.5命名管道8.5.1命名管道的創(chuàng)建內(nèi)容提要9:4085/2678.5.2命名管道的使用8.6消息隊列8.6.1消息隊列的創(chuàng)建與打開8.6.2向消息隊列中發(fā)送消息8.6.3從消息隊列中接收消息8.6.4消息隊列的控制8.6.5綜合示例8.8本章小結(jié)8.9本章習(xí)題第八章進程間通信9:4086/267

本章首先介紹Linux下進程間通信的相關(guān)內(nèi)容;然后介紹

Linux平臺下進程間通信相互通信的方法,包括共享內(nèi)存、信號量、管道通信、命名管道、消息隊列;最后結(jié)合具

體的項目案例,闡述進程間通信的相關(guān)操作的具體應(yīng)用。本節(jié)學(xué)習(xí)目標(biāo):√共享內(nèi)存√信號量√管道通信√命名管道√消息隊列8.1進程間通信概述

Linux系統(tǒng)是多任務(wù)多進程的操作系統(tǒng),對于大型的應(yīng)用系統(tǒng)而言,通常需要多個任務(wù)多個進程相互協(xié)作共同完成,而進程的地址空間又是各自獨立的,所以需要進程間進行通信。進程間的通信(Internet

ProcessConnection簡稱IPC)是指多個進程間相互協(xié)調(diào),進行信息交換,相互交流的方法。Linux下進程間進行相互通信的方法包括共享內(nèi)存、信號量、管道、命名管道、消息隊列等。下面對Linux下的進程間的通信方法做個簡單介紹。

共享內(nèi)存:共享內(nèi)存是指由一個進程創(chuàng)建并且能夠被其它進程訪問的內(nèi)存段。共享內(nèi)存是進程間通信方式最快的IPC方式,經(jīng)常與信號量等通信機制配合使用,通信速度最快、運行效率最高。9:40in87/2678.1進程間通信概述9:4088/267

信號量:信號量在形式上是一個計數(shù)器,主要用來協(xié)調(diào)進程間或同一個進程內(nèi)不同線程間同時訪問共享資源的問題。所以,信號量也稱為一種信號鎖,保證同一時刻只有一個進程或線程訪問共享資源,其余進程或線程無法訪問該共享資源;信號量也是一種同步機制,同一時刻可以有多個進程訪問共享資源。

管道:管道在形式上是一種文件,主要用在具有親緣關(guān)系的進程間的通信。管道是一種半雙工的通信方式,它的顯著特點是管道有讀入端和寫入端,數(shù)據(jù)只能單向流動。和共享內(nèi)存相比,管道通信相對慢些,但是它用起來方便很多,系統(tǒng)開銷也小。8.1進程間通信概述9:4089/267

命名管道:命名管道是管道中的一種,具有管道的所有功能和特點。命名管道是一個設(shè)備文件,不僅可用在具有親緣關(guān)系的進程間的通信,而且也可用在不具有親緣關(guān)系的進程間。命名管道要求提供一個路徑名與它關(guān)聯(lián)的文件,只要可以訪問這個路徑文件的進程,都可以進程間的相互通信。

消息隊列:消息隊列是存放在操作系統(tǒng)內(nèi)核中的消息鏈表,每個消息隊列由消息隊列標(biāo)識符標(biāo)示。消息隊列存放在內(nèi)核中,所以只有重啟操作系統(tǒng)或主動刪除一個消息隊列,消息隊列才會消除。消息隊列具有傳遞信息量大、可以承載各種格式的字節(jié)流和可以動態(tài)設(shè)置緩沖區(qū)大小的優(yōu)點。8.2共享內(nèi)存9:4090/267

在Linux系統(tǒng)中,共享內(nèi)存是由一個進程創(chuàng)建并且能夠被其它進程訪問的內(nèi)存段。每個進程所創(chuàng)建的共享內(nèi)存在操作系統(tǒng)內(nèi)核中維護著一個與之相應(yīng)的數(shù)據(jù)結(jié)構(gòu)

shmid_ds,它的具體定義如下所示:8.2共享內(nèi)存9:4091/2678.2共享內(nèi)存9:4092/267???????

這個結(jié)構(gòu)詳細(xì)描述了共享內(nèi)存的各種屬性,它們的具體含義如下所示:shm_perm:表示共享內(nèi)存的用戶ID、組ID等信息;shm_segsz:以字節(jié)為單位表示共享內(nèi)存的大?。籹hm_lkcnt:表示共享內(nèi)存段鎖定的時間大??;shm_cpid:表示創(chuàng)建共享內(nèi)存的進程ID;shm_lpid:表示最后一次操作共享內(nèi)存的進程ID;shm_nattch:表示當(dāng)前使用共享內(nèi)存的進程數(shù);shm_atime:表示最后一次附加共享內(nèi)存的時間;8.2共享內(nèi)存9:4093/267shm_dtime:表示最后一次分離共享內(nèi)存的時間;shm_ctime:表示最后一次修改共享內(nèi)存的時間;下面給出基于上述共享內(nèi)存數(shù)據(jù)結(jié)構(gòu)的函數(shù)調(diào)用。1共享內(nèi)存的創(chuàng)建9:4094/267

創(chuàng)建共享內(nèi)存的函數(shù)是shmget。系統(tǒng)通過調(diào)用它在程序中完成共享內(nèi)存的創(chuàng)建工作。在Linux系統(tǒng)終端中使用幫助命令“man

shmget”,得到共享內(nèi)存的創(chuàng)建函數(shù)信息如下:#include

<sys/ipc.h>#include

<sys/shm.h>int

shmget(key_t

key,

size_t

size,

int

shmflg);1共享內(nèi)存的創(chuàng)建9:4095/267

shmget:該函數(shù)的返回類型為整型,用于創(chuàng)建進程的共享內(nèi)存。key參數(shù)表示由ftok生成的共享內(nèi)存鍵。size參數(shù)表示共享內(nèi)存的大小,若是新創(chuàng)建一個共享內(nèi)存則size須大于0;若是訪問已經(jīng)存在的共享內(nèi)存則size為0。

shmflg參數(shù)表示共享內(nèi)存的操作標(biāo)志位,用于設(shè)置共享內(nèi)存的訪問權(quán)限,若shmflg參數(shù)取值為IPC_CREATE,則表示系統(tǒng)將參數(shù)key與其它的共享內(nèi)存key進行比較,如果相同則返回已經(jīng)存在的共享內(nèi)存區(qū)的標(biāo)識符,如果不同則新建一個共享內(nèi)存區(qū)并返回其標(biāo)識符;若shmflg參數(shù)取值為IPC_EXCL,則表示無意義;若shmflg參數(shù)取值為IPC_CREATE

|

IPC_EXCL,表示如果發(fā)現(xiàn)信號集已經(jīng)存在,則返回-1。1共享內(nèi)存的創(chuàng)建9:4096/267

函數(shù)shmget調(diào)用成功返回共享內(nèi)存的引用標(biāo)示符,同時該共享內(nèi)存的shmid_ds結(jié)構(gòu)被初始化;否則調(diào)用失敗返回-1。2共享內(nèi)存的附加9:4097/267

共享內(nèi)存的附加函數(shù)是shmat。系統(tǒng)通過調(diào)用它在程序中完成共享內(nèi)存的附加工作。在Linux系統(tǒng)終端中使用幫助命令“man

shmat”,得到共享內(nèi)存的附加函數(shù)信息如

下:#include

<sys/types.h>#include

<sys/shm.h>void

*shmat(int

shmid,

const

void

*shmaddr,

int

shmflg);2共享內(nèi)存的附加9:4098/267

shmat:該函數(shù)的返回類型為指針,指向共享內(nèi)存的地址,用于附加進程的共享內(nèi)存。shmid參數(shù)表示附加的共享內(nèi)

存的引用標(biāo)示符。shmflg參數(shù)表示共享內(nèi)存的讀寫操作方式。shmaddr參數(shù)表示共享內(nèi)存的附加地址空間,若

shmaddr參數(shù)取值為空,則表示由內(nèi)核選擇一個空閑的內(nèi)存區(qū);若shmaddr參數(shù)取值為非空,并且shmflg參數(shù)指定為SHM_RND值則附加地址為共享內(nèi)存的低端邊界地址后的地址,否則附加地址為shmaddr指定的地址。通常shmaddr參數(shù)設(shè)置為NULL。

函數(shù)shmat調(diào)用成功返回共享內(nèi)存的附加地址;否則調(diào)用失敗返回-1。3共享內(nèi)存的分離9:4099/267

共享內(nèi)存的分離函數(shù)是shmdt。系統(tǒng)通過調(diào)用它在程序中完成共享內(nèi)存的分離工作。在Linux系統(tǒng)終端中使用幫助命令“man

shmdt”,得到共享內(nèi)存的分離函數(shù)信息如

下:#include

<sys/types.h>#include

<sys/shm.h>int

shmdt(const

void

*shmaddr);3共享內(nèi)存的分離9:40100/267

shmdt:該函數(shù)的返回類型為整型,用于分離進程的共享內(nèi)存。shmaddr參數(shù)為函數(shù)shmat的返回值。進程與共享內(nèi)存分離后,shmid_ds中的shm_nattch會自動減1。若

shm_nattch的值減為0后,表示沒有任何進程使用此共享內(nèi)存,該共享內(nèi)存將被系統(tǒng)刪除。函數(shù)shmdt調(diào)用成功返回0;否則調(diào)用失敗返回-1。4共享內(nèi)存的控制9:40101/267

共享內(nèi)存的控制函數(shù)是shmctl。系統(tǒng)通過調(diào)用它在程序中完成共享內(nèi)存的控制工作。在Linux系統(tǒng)終端中使用幫助命令“man

shmctl”,得到共享內(nèi)存的控制函數(shù)信息如

下:#include

<sys/ipc.h>#include

<sys/shm.h>int

shmctl(int

shmid,

int

cmd,

struct

shmid_ds

*buf);4共享內(nèi)存的控制9:40102/267

shmctl:該函數(shù)的返回類型為整型,用于對共享內(nèi)存的控制。shmid參數(shù)表示附加的共享內(nèi)存的引用標(biāo)示符。buf參數(shù)為指向shmid_ds結(jié)構(gòu)體的指針。cmd參數(shù)為操作標(biāo)志位,若cmd參數(shù)取值為IPC_RMID則表示刪除由shmid標(biāo)示的共享內(nèi)存區(qū);若cmd參數(shù)取值為IPC_SET則表示設(shè)置共享內(nèi)存區(qū)shmid_ds結(jié)構(gòu);cmd參數(shù)取值為IPC_STAT則表示將共享內(nèi)存區(qū)shmid_ds結(jié)構(gòu)存儲到buf指向的地址中。函數(shù)shmdt調(diào)用成功返回0;否則調(diào)用失敗返回-1。5綜合示例9:40103/267

本節(jié)最后,通過利用共享內(nèi)存的相關(guān)函數(shù)進行系統(tǒng)調(diào)用,來演示如何創(chuàng)建和使用共享內(nèi)存,加強對進程通信的理解。共享內(nèi)存的讀函數(shù)

my_shmget_reader如范例8-1a所示,共享內(nèi)存的寫函數(shù)my_shmget_writer如范例8-1b所示。例8-1a

my_shmget_reader.c/****my_shmget_reader.c***/例8-1b

my_shmget_writer.c/****

my_shmget_writer.c***/在VIM編輯器中具體闡述代碼在eclipse集成開發(fā)環(huán)境IDE中編譯、調(diào)試、運行代碼8.3信號量9:40104/267

在Linux系統(tǒng)中,信號量實質(zhì)是整數(shù)計數(shù)器,常用于處理進程或線程的對共享資源的同步和互斥問題。同步共享資源要求同一時刻允許多個進程或線程訪問該資源;互斥共享資源要求同一時刻只允許一個進程或線程訪問該資源。這里的資源可以是某種硬件資源、一段代碼或一個變量等。當(dāng)信號量的值大于或等于0時,表示并發(fā)進程或線程可使用的資源實體數(shù);信號量小于0表示正在等待使用共享資源的進程數(shù)。8.3信號量

每個進程所創(chuàng)建的信號量在操作系統(tǒng)內(nèi)核中維護著一個與之相應(yīng)的數(shù)據(jù)結(jié)構(gòu)semid_ds實例,它的具體定義如下所示:9:40105/2678.3信號量9:40106/267

每個進程所創(chuàng)建的信號量在操作系統(tǒng)內(nèi)核中維護著一個與之相應(yīng)的數(shù)據(jù)結(jié)構(gòu)semid_ds實例,它的具體定義如下:struct

semid_ds

{

struct

ipc_perm

sem_perm;

/*

Ownership

andpermissions

*/*sem_base;

/*

Pointer

of

first

sem

*/sem_otime;

/*

Last

semop

time

*/sem_ctime;

/*

Last

change

time

*/struct

semtime_ttime_t?unsigned

short

sem_nsems;

/*

No.

of

semaphoresin

set

*/};8.3信號量9:40107/267

這個結(jié)構(gòu)詳細(xì)描述了信號集的各種屬性,它們的具體含義如下所示:sem_perm:表示信號集的用戶ID、組ID、權(quán)限等信息;

sem_base:表示信號量的基地址,指向信號集中第一個信號量的地址;sem_otime:表示最后一次調(diào)用semop函數(shù)的時間;sem_ctime:表示最后一次改變該信號集的時間;sem_nsems:表示信號集中信號量的個數(shù);8.3信號量9:40108/267

這個結(jié)構(gòu)詳細(xì)描述了信號集中信號量的各種屬性,它們的具體含義如下所示:struct

sem{ushort

semval;pid_t

sempid;ushort

semncnt;ushort

semzcnt;};8.3信號量9:40109/267

這個struct

sem結(jié)構(gòu)詳細(xì)描述了它的各種屬性,它們的具體含義如下所示:semval:表示信號量的值;sempid:表示最近一次訪問共享資源的進程ID號;semncnt:表示等待利用資源的進程數(shù);semzcnt:表示全部資源被獨占的進程數(shù);下面給出基于上述信號集和信號量數(shù)據(jù)結(jié)構(gòu)的函數(shù)調(diào)用。1信號集的創(chuàng)建9:40110/267

信號集的創(chuàng)建函數(shù)是semget。系統(tǒng)通過調(diào)用它在程序中完成信號集的創(chuàng)建工作。在Linux系統(tǒng)終端中使用幫助命令“man

semget”,得到信號集的創(chuàng)建函數(shù)信息如下:#include

<sys/types.h>#include

<sys/ipc.h>#include

<sys/sem.h>int

semget(key_t

key,

int

nsems,

int

semflg);1信號集的創(chuàng)建9:40111/267

semget:該函數(shù)的返回類型為整型,用于創(chuàng)建或打開一個信號集。key參數(shù)表示由ftok生成的信號集鍵。nsems參數(shù)表示創(chuàng)建信號集中信號量的個數(shù),若是新創(chuàng)建一個信號集則nsems須大于0;若是訪問已經(jīng)存在的信號集則

nsems為0。semflg參數(shù)表示信號集的操作標(biāo)志位,用于設(shè)置信號集的訪問權(quán)限,若semflg參數(shù)取值為

IPC_CREATE,則表示系統(tǒng)將參數(shù)key與其它的信號集key進行比較,如果相同則返回已經(jīng)存在的信號集標(biāo)識符,如果不同則新建一個信號集并返回其標(biāo)識符;若semflg

參數(shù)取值為IPC_EXCL,則表示無意義;若semflg參數(shù)取

值為IPC_CREATE

|

IPC_EXCL,表示如果發(fā)現(xiàn)信號集已經(jīng)存在,則返回-1。1

ftok函數(shù)深度解析9:40112/267

關(guān)于ftok函數(shù),先不去了解它的作用來先說說為什么要用它,共享內(nèi)存,消息隊列,信號量它們?nèi)齻€都是找一個

中間介質(zhì),來進行通信的,這種介質(zhì)多的是。就是怎么

區(qū)分出來,就像唯一一個身份證來區(qū)分人一樣。你隨便

來一個就行,就是因為這。只要唯一就行,就想起來了

文件的設(shè)備編號和節(jié)點,它是唯一的,但是直接用它來

作識別好像不太好,不過可以用它來產(chǎn)生一個號。ftok()就出場了。ftok函數(shù)具體形式如下:1

ftok函數(shù)深度解析9:40113/267key_t

ftok(const

char

*pathname,

int

proj_id);

其中參數(shù)fname是指定的文件名,這個文件必須是存在的而且可以訪問的。id是子序號,它是一個8bit的整數(shù)。即范圍是0~255。當(dāng)函數(shù)執(zhí)行成功,則會返回key_t鍵值,

否則返回-1。在一般的UNIX中,通常是將文件的索引節(jié)

點取出,然后在前面加上子序號就得到key_t的值。有關(guān)該函數(shù)的三個常見問題:

1.pathname是目錄還是文件的具體路徑,是否可以隨便設(shè)置2.pathname指定的目錄或文件的權(quán)限是否有要求

3.proj_id是否可以隨便設(shè)定,有什么限制條件1

ftok函數(shù)深度解析9:40114/267解答:

1、ftok根據(jù)路徑名,提取文件信息,再根據(jù)這些文件信息及project

ID合成key,該路徑可以隨便設(shè)置。

2、該路徑是必須存在的,ftok只是根據(jù)文件inode在系統(tǒng)內(nèi)的唯一性來取一個數(shù)值,和文件的權(quán)限無關(guān)。

3、proj_id是可以根據(jù)自己的約定,隨意設(shè)置。這個數(shù)字,有的稱之為project

ID;在UNIX系統(tǒng)上,它的取值是1到255;ftok()函數(shù)深度解析

/u013485792/article/details/5076422

41

ftok函數(shù)深度解析9:40115/2671

ftok函數(shù)深度解析9:40116/2671信號集的創(chuàng)建9:40117/267

函數(shù)調(diào)用成功返回信號集的引用標(biāo)示符,同時該共享內(nèi)存的shmid_ds結(jié)構(gòu)被初始化;否則調(diào)用失敗返回-1。2信號集的操作9:40118/267

信號量的值和資源使用情況有關(guān)系,當(dāng)信號量的值大于或等于0時,表示并發(fā)進程或線程可使用的資源實體數(shù);信號量小于0表示正在等待使用共享資源的進程數(shù)。信號量值的改變通過在PV操作中調(diào)用信號量的操作函數(shù)

semop,來實現(xiàn)信號量的改變。2信號集的操作9:40119/267

信號量的操作函數(shù)是semop。系統(tǒng)通過調(diào)用它在程序中完成信號量的操作工作。在Linux系統(tǒng)終端中使用幫助命令“man

semop”,得到信號量的操作函數(shù)信息如下:#include

<sys/types.h>#include

<sys/ipc.h>#include

<sys/sem.h>

int

semop(int

semid,

struct

sembuf

*sops,

unsignednsops);2信號集的操作9:40120/267sem_op;

/*

semap

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論