POSIX標準整體分析html
POSIX,全稱爲可移植性操做系統接口,是一種關於信息技術的IEEE標準。它包括了系統應用程序接口(API),以及實時擴展(C語言)。node
該標準的目的是定義了標準的基於UNIX操做系統的系統接口和環境來支持源代碼級的可移植性。如今,標準主要提供了依賴C語言的一系列標準服務,再未來的版本中,標準將致力於提供基於不一樣語言的規範。linux
該標準對核心需求部分定義了一系列任何編程語言都通用的服務,這一部分服務主要從其功能需求方面闡述,而非定義依賴於編程語言的接口。語言規範主要有兩部分組成。一部分包括了訪問核心服務的編程語言的標準接口,這些核心服務爲標準中基於編程語言的核心需求部分所定義;另外一部分包含了一個特殊語言服務的標準接口。基於任何語言,與該標準一致的執行都必須遵循語言規範的任何章節。ios
該標準一共被分爲四個部分:程序員
1) 陳述的範圍和一系列標準參考(第一章);正則表達式
2) 定義和總概念;(第二章)shell
3) 各類接口設備;(第三章到第十七章)數據庫
4) 頭文件;(第十八章)編程
該標準的主要目的有:數組
1) 面向應用
2) 定義接口,而不是它的具體實現;
3) 涉及資源和可移植性,而非對象;
4) 基於c語言;
5) 無超級用戶,無系統管理;
6) 最小限度的接口,最小限度的定義;
7) 應用領域普遍;
8) 對之前的實現進行最小限度改變;
9) 對原有程序代碼作最小的修改;
10) 實時擴展;
二 概述
2.1 範圍
定義範圍的關鍵要素有:
(1)定義足夠的一套功能適用於實時應用程序領域的重要部分;
(2)定義足夠的實現規範和性能相關的函數,以便容許實時應用程序完成系統的肯定性的響應;
2.2 一致性
系統須支持標準中定義的接口,系統可以提供標準中沒有要求到的函數和工具。在遵循於該標準的實現中,一種一致性文檔是須要用到的,它必須具備與該標準相同的結構,包含有全名,數字,和標準所指示的日期,以及頭文件<limits.h>和<unistd.h>中的界限值等等。該一致性文檔詳細說明了標準中定義的執行行爲。該標準要求了應用程序的一致性,全部遵循標準的應用程序都使用基於C語言的服務。
2.3 定義
1) 術語
該標準中定義了一系列術語,如一致性文檔,被定義的實現,可能性,無用的特性等,還定義了一些通用名詞,如絕對路徑,存取模式,地址空間,適當權限,定時器,異步I/O操做,後臺進程,後臺進程組,塊文件,阻塞進程等等。
2) 基本概念
擴展安全控制;文件存取容許;文件級別;文件名可移植性;路徑名的決定;
3) 錯誤號
大部分函數都在外部變量errno中提供了錯誤號,定義以下:
extern int errno;
4) 簡單系統的數據類型
這些數據類型在頭文件<sys/types.h>中定義,它包含了至少如下類型:
dev_t |
用於設備號 |
gid_t |
用於進程標誌符 |
ino_t |
用於文件序列號 |
inode_t |
用於一些文件參數 |
nlink_t |
用於鏈接內容 |
off_t |
用於文件大小 |
pid_t |
用於進程或進程組標誌符 |
size_t |
在c標準(2)中定義 |
ssize_t |
用於返回字節數和錯誤標誌的函數 |
uid_t |
用於用戶標誌符 |
5) 環境描述
當一個進程開始執行時,將調用一個表示環境的字符串數組,這個數組爲外部變量environ所指向,其定義以下:
extern char **environ;
6) 其餘
在該章中,標準還整體介紹了c語言定義的一些標誌符,數字方面的限制,以及一些符號常量,這些在之後的章節中都會一一出現。
三 進程原語
3.1 進程的建立和執行
1) 進程建立
函數原型:
#include <unistd.h>
pid_t fork(void)
函數功能:
調用時須要引用的頭文件是<unistd.h>,fork()建立了一個新的進程。子進程中返回0,父進程中返回子進程ID,出錯返回-1。
2) 執行一個文件
函數原型:
#include <unistd.h>
int exec1(const char *path, const char *arg, …);
int execv(const char *path, const *char argv[] );
int execle(const char *path, const char *arg, …);
int execve(const char *path, const *char argv[], char *const envp[]);
int execlp(const char *file, const char *arg. …);
int execvp(const char *file, char *const argv[]);
函數功能:
exec系列的函數用一個新的進程映像替代了當前的進程的正文、數據、堆和棧段,這個新的進程映像建立於一個規則的可執行文件,叫作新進程映像文件。執行成功無返回值由於調用進程映像覺得新的進程映像所覆蓋。
3) 創建fork處理程序
函數原型:
#include <pthread.h>
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
函數功能:
調用pthread_atfork(),創建fork處理程序,能夠清除鎖狀態。
3.2 進程的終止
進程的終止有兩種狀況:
(1)從main()函數返回時或者執行exit()或_exit()函數時正常的終止;
(2)被abort()函數請求或者接受到一些信號時不正常的終止;
1) 等待進程終止
函數原型:
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid,int *stat_loc.int options);
函數功能:
wait()和waitpid()容許調用進程得到它的一個子進程的狀態信息。wait()函數將掛起調用進程直到得到了它的子進程的狀態信息,或者是直到得到一個終止進程信號;若是pid=-1而且options=0,waitpid()函數功能將和waitpid()相同,不然它的功能將依據pid和options的值而改變。
區別:在一個子進程終止前,wait()使其調用者阻塞,而waitpid()有一個選項,可以使調用者不阻塞。waitpid()並不等待在起調用以後的第一個終止子進程,它有若干個選項,能夠控制它所等待的進程。
2) 終止一個進程
函數原型:
#include <stdlib.h>
void _exit(int status);
函數功能:
_exit()函數將終止一個調用進程,該函數不能返回給其調用者。
說明:exit()和_Exit()是由ISO C說明的,而_exit()是由POSIX.1說明的。
3.3 信號
在頭文件<signal.h>中聲明瞭sigset_t類型和sigaction結構。完成所定義的信號分三類:必需的信號、任務控制信號、內存保護信號。分別以下表:
必需信號
符號常量 |
描述 |
SIGABRT |
非正常終止信號 |
SIGALRM |
超時信號 |
SIGFPE |
錯誤運算操做 |
SIGHUP |
爲控制中斷所檢測到的掛斷 |
SIGILL |
無效硬件信號的檢測 |
SIGINT |
交互式信號 |
SIGKILL |
終止信號 |
SIGPIPE |
寫信號 |
SIGQUIT |
交互式終止信號 |
SIGSEGV |
無效內存引用檢測信號 |
SIGTERM |
終止信號 |
SIGUSR1 |
保留信號 |
SIGUSR2 |
保留信號 |
任務控制信號
符號常量 |
描述 |
SIGCHLD |
子進程終止或中止 |
SIGCONT |
中止後繼續 |
SIGSTOP |
中止信號 |
SIGTSTP |
交互式的中止信號 |
SIGTTIN |
從控制終端讀 |
SIGTTOU |
寫到控制終端 |
內存保護信號
符號常量 |
描述 |
SIGBUS |
獲取內存中不肯定的部分 |
每個進程有一個進程標記(process mask),它定義了一組產生但被阻塞傳遞的信號集。sigaction(),sigpromask(),sigsuspend()函數控制這個進程標記的行爲。
1) 送一個信號到進程
函數原型:
#include <sys/types.h>
#include<signal.h>
int kill(pid_t pid, int sig)
函數功能:
該函數發送一個信號到一個由pid指明的進程或者進程組,sig標誌了信號類型,其值是0或者上表中的值。若是發送成功,返回’0’,不然返回’1’。
2) 操縱信號集
函數原型:
#include<signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set,int signo);
函數功能:
sigemptyset()初始化由set指向的信號集,清除其中全部信號;
sigfillset()初始化由set指向的信號集,使其包括全部信號;
全部應用程序在使用信號集前,要對該信號集調用sigemptyset()和sigfillset()一次;
sigaddset()將一個信號添加到先有集中;
sigdelset()從信號集中刪除一個信號;
sigismember()測試一指定位。
3) 檢測和更改信號的行爲
函數原型:
#include<signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
函數功能:
該函數容許調用函數檢查與肯定的信號相聯繫的行爲,參數sig肯定了信號,sigaction結構在頭文件<signal.h>中被定義,描述了所採起的行爲。若是參數act不爲null,它指向一個結構,它指定了與信號相聯繫的行爲。若是參數oact不爲null,先前與信號相聯繫的行爲將被存儲到由oact指向的地方。
4) 檢查和改變阻塞信號
函數原型:
#include<signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
函數功能:
該函數sigprocmask能夠檢測或更改其信號屏蔽字。首先,若oset是非空指針,那麼進程的當前信號屏蔽字經過oset返回。其次,若set是一個非空指針,則參數how指示如何修改當前信號屏蔽字。若是set是空指針,則不改變該進程的信號屏蔽字,how的值也無心義。
5) 檢查未定的信號
函數原型:
#include<signal.h>
int sigpending(sigset_t *set);
函數功能:
該函數返回一個信號集,其中的各個信號對於調用進程是阻塞的而不能遞送,於是也必定是當前未決的。該信號集經過set參數返回。
6) 等待一個信號
函數原型:
#include<signal.h>
int sigsuspend(const sigset_t *sigmask);
函數功能:
該函數提供了在一個原子操做中先回覆信號屏蔽字,而後使進程休眠。
將進程的信號屏蔽字設置爲sigmask所指向的值。在捕捉到一個信號或發生了一個會停止該進程的信號以前,該進程被掛起。若是捕捉到了一個信號好並且從該信號處理程序返回,則sigsuspend()返回,而且該進行的信號屏蔽字設置爲調用sigsuspend()以前的值。
注意,該函數沒有成功返回值。若是它返回到調用者,則老是返回-1,並將errno設置爲EINTR(表示一個被中斷的系統調用)。
Sigsuspend()的另外一種應用時等待一個信號處理程序設置一個全局變量。
7) 同步接受一個信號
函數原型:
#include<signal.h>
int sigwaitinfo(const sigset_t *set, siginfo_t *info);
int sigtimedwait(const sigset_t *set,siginfo_ *info, const struct timespec *timeout);
函數功能:
該函數從參數set所肯定的信號集中選擇一個未定的信號出來。若是該函數成功,返回一個信號數;不然返回-1。
8) 排隊一個信號到進程
函數原型:
#include<signal.h>
int sigqueue(pid_t pid,int signo, const union sigval value);
函數功能:
該函數功能是使由signo肯定的信號將參數value所肯定的值發送到由pid指明的進程中去。
3.4 定時器操做
1) 調度警報
函數原型:
#include<unistd.h>
unsigned int alarm(unsigned int seconds);
函數功能:
使用該函數能夠設置一個計時器,在未來某個指定的時間該計時器會超時。當計時器超時時,產生SIGALRM信號。若是不忽略或者不捕捉該信號,則其默認動做時終止調用該函數的進程。
2) 掛起進程的執行
函數原型:
#include<unistd.h>
int pause(void);
函數功能:
該函數掛起一個調用進程直至捕捉到一個信號,這個信號或者執行信號跟蹤功能或者是終止該進程。若是是終止進程,該函數不返回;若是是執行信號跟蹤功能,則該函數在信號跟蹤函數返回後也要返回。
3) 延遲進程的執行
函數原型:
#include<unistd.h>
unsigned int sleep(unsigned int seconds);
函數功能:
該函數使當前進程從執行狀態轉化爲掛起狀態,直到參數seconds所指定的一段實時時間過去後,或者是一個喚醒信號跟蹤功能或終止進程功能的信號到來。該掛起時間因爲系統的其餘調度活動可能會比要求的時間長。
四 進程環境
4.1 進程標誌符
1) 得到進程和父進程的ID
函數原型:
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
函數功能:
getpid()返回調用進程的進程ID,
getppid()返回調用進程的父進程ID.
4.2 用戶ID
1) 得到真實用戶,有效用戶,真是組,有效組的ID
函數原型:
#include <unistd.h>
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
函數功能:
getuid()返回調用進程的真實用戶ID, geteuid()返回調用進程的有效用戶ID,getgid()返回調用進程的真實組ID,getegid()返回調用進程的有效組的ID。
2) 設置用戶和組的ID
函數原型:
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
int seteuid(uid_t uid);
int setegid(gid_t gid);
函數功能:
這兩個函數分別根據進程的權限設置真實用戶ID,有效用戶ID,真實組ID,有效組ID。
3) 得到輔助組ID
函數原型:
#include <unistd.h>
int getgroups(int gidsetsize, gid_t grouplist[]);
函數功能:
該函數在隊列的組列表中填入調用進程的輔助組ID。參數gidsetsize肯定了組列表中的元素個數。
4) 得到用戶名
函數原型:
#include <unistd.h>
char *getlogin(void)
函數功能:
該函數返回一個指針,指向與調用進程相關的用戶名。
4.3 進程組
1) 得到進程組ID
函數原型:
#include <unistd.h>
pid_t getpgrp(void);
函數功能:
該函數返回調用進程的進程組ID。
2) 建立會話而且設置進程組ID
函數原型:
#include <unistd.h>
pid_t setsid(void)
函數功能:
若是調用進程不是進程組的組長,則該函數將建立一個新會話。結果將發生下面三件事:一、該進程成爲一個新進程組的組長進程。此時,該新進程是新會話中惟一的進程。二、該進程成爲一個新進程組的組長進程。新進程組ID是該調用進程的進程ID。三、該進程沒有控制終端。若是再調用setsid()以前該進程有一個控制終端,那麼這種聯繫也會被中斷。
3) 爲做業控制設置進程組ID
函數原型:
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
函數功能:
如{_POSIX_JOB_CONTROL}被定義,則該函數用來加入已經存在的進程組或者建立一個新的進程組。
4.4 系統標誌
1) 得到系統名
函數原型:
#include<sys/utaname.h>
int uname(struct utsname *name);
函數功能:
該函數返回與當前主機與操做系統有關的信息。經過該函數的參數向其傳遞一個utsname結構的地址,而後改函數填寫此結構。
struct utsname{
char sysname[]; /*name of the operation system*/
char nodename[];/*name of this node*/
char release[]; /*current release of operating system*/
char version[]; /*current version of this release*/
char machine[]; /*name of hardware type*/
};
4.5 時間
1) 獲得系統時間
函數原型:
#include<time.h>
time_t time(time_t *calptr);
函數功能:
該函數返回自從公元1970年1月1日00:00:00以來的某個時間值,以秒爲單位。參數calptr指向一個時間值所存儲的地方。
2) 得到進程時間
函數原型:
#include<sys/times.h>
clock_t times(struct time *buffer);
函數功能:
參數buffer指向一個結構,該函數向該結構填寫有關時間的信息。clock_t和tms結構在<sys/times.h>中定義。
4.6 環境變量
1) 獲取環境
函數原型:
#include<stdlib.h>
char *getenv(const char *name);
函數功能:
該函數在環境列表查找字符串name=value,返回指向value的指針。若是沒有找到,則返回null。
2) 設置環境
函數原型:
#include<stdlib.h>
int putenv(char *str);
int setenv(const char *name, const char *value, int rewrite);
int unsetenv(const char *name);
函數功能:
putenv()取形式爲name=value的字符串,將其放到環境表中。若是name已經存在,則先刪除其原來的定義。
setenv()將name設置爲value。若是再環境中name已經存在,那麼若rewrite非0,則首先刪除其現有的定義,若rewrite爲0,則先不刪除現有定義。
unsetenv()刪除name的定義。
4.7 終端標誌
1) 產生終端路徑
函數原型:
#include<stdio.h>
char *ctermid(char *s);
函數功能:
該函數產生一個字符串,做爲路徑名,提交到當前進程的當前控制終端, 用來肯定控制終端的名字。此函數的主要做用是幫助提升向其餘操做系統的可移植性。
2) 肯定終端設備名
函數原型:
#include <unistd.h>
int isatty(int fildes);
char *ttyname(int fildes);
函數功能:
ttyname()返回一個指針指向一個字符串,它包含了該文件描述符上打開的終端設備的路徑名;
若是fildes是一個有效的與終端聯繫的文件描述符,isatty()返回’1’,不然返回’0’。
4.8 可配置的系統變量
1) 得到可配置的系統變量
函數原型:
#include<unistd.h>
long sysconf(int name);
函數功能:
該函數提供了一個應用方法來決定可配置系統變量的當前值。參數name表明了所查詢的系統變量。
五 文件和目錄
5.1 目錄
1) 目錄的入口形式
頭文件<dirent.h>定義了一個結構和目錄程序用到的類型,沒有肯定的文件內部格式。readdir()返回了一個指針指向一個類型對象struct dirent。
2) 目錄操做
函數原型:
#include<sys/types.h>
#include<dirent.h>
dir *opendir(const char *dirname);
struct dirent *readdir(dir *dirp);
void rewinddir(dir *dirp);
int closedir(dir *dirp);
函數功能:
opendir()根據參數dirname打開一個目錄流;readdir()返回一個指針,它指向一個目錄流中當前位置的目錄入口,目錄流由參數dirp指向;rewinddir()重置目錄流的位置到目錄的起點;closedir()關閉目錄流,如成功,則返回「0」值。
5.2 工做目錄
1) 改變當前的工做目錄
函數原型:
#include<unistd.h>
int chdir(const char *path);
函數功能:
path指向當前目錄的路徑名。該函數使命名的目錄成爲當前的工做目錄。
2) 得到工做目錄路徑名
函數原型:
#include<unistd.h>
char *getcwd(char *buf,size_t size);
函數功能:
該函數複製當前工做目錄的絕對路徑名到buf所指向的隊列中。
5.3 基本文件的建立
1) 打開一個文件
函數原型:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcnt1.h>
int open(const char *path, int oflag,…);
函數功能:
open()在文件和文件描述符之間創建了一個鏈接,它建立了一個指向一個文件的打開文件描述,參數path指向文件的路徑名。
2) 建立一個新文件或者重寫一個已經存在的文件
函數原型:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcnt1.h>
int creat(const char *path, mode_t mode);
函數功能:
該函數建立一個新文件。調用creat(path, mode)至關於open(path, o_wronly|o_creat|o_trunc,mode);
3) 設置文件的建立標記
函數原型:
#include<sys/types.h>
#include<sys/stat.h>
mode_t umask(mode_t cmask);
函數功能:
umask()設置進程的文件模式建立標記到cmask,而且返回原來的標記值。
4) 連接到一個文件
函數原型:
#include<unistd.h>
int link(const char *existingpath ,const char *newpath);
函數功能:
參數existingpath指向路徑名來命名存在文件,參數newpath指向一個路徑名,它命名了一個建立的新的目錄入口。該函數爲已存在的文件自動的建立一個新的鏈接,而且將文件鏈接數加1。若是newpath已經存在,則返回出錯。
5) 建立一個符號連接
函數原型:
#include <unistd.h>
int symlink(const char *path1, const char *path2);
函數功能:
該函數建立了一個指向path1的新目錄項path2,在建立此符號連接時,不須要求path1已經存在。
6) 打開符號連接
函數原型:
#include <unistd.h>
int symlink(const char *restrict path, char *restrict buf, size_t bufsize);
函數功能:
打開符號連接,此函數組合了open,read,close的全部操做。若是此函數成功執行,則返回讀入buf的字節數。
5.4 文件建立
1) 生成一個目錄
函數原型:
#include<sys/types.h>
#include<sys/stat.h>
int mkdir(const char *path,mode_t mode);
函數功能:
該函數依據參數path建立一個新的目錄。新目錄的容許位根據mode初始化。
2) 建立一個FIFO類型的文件
函數原型:
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
函數功能:
mkfifo()建立一個新的fifo類型文件,它由pathname指向的路徑名命名。
FIFO有下面兩種用途:一、FIFO由shell命令使用以便將數據從一條管道線傳到另外一條,爲此無需建立中間臨時文件。二、FIFO用於客戶進程-服務器進程應用程序中,以在客戶進程和服務器進程之間傳遞數據。
5.5 文件的移動
1) 移動目錄入口
函數原型:
#include<unistd.h>
int link(const char *existingpath ,const char *newpath);
函數功能:
該函數刪除目錄項,並將有pathname所引用文件的連接計數減1。若是還有指向該文件的其餘連接,則仍能夠經過其餘連接訪問該文件的數據。若是出錯,則不對該文件作任何更改。
2) 移去一個目錄
函數原型:
#include<unistd.h>
int rmdir(const char *path)
函數功能:
移除一個路徑爲path的目錄。
3) 重命名一個文件
函數原型:
int rename(const char *old,const char *new);
函數功能:
該函數改變一個文件的名字,參數old指向被重命名文件的路徑名,參數new指向文件的新路徑名。
5.6 文件特徵
1) 得到一個路徑下的信息
函數原型:
#include <sys/stat.h>
int stat(const char *restrict path, struct stat *restrict buf);
函數功能:
該函數得到路徑下的文件信息,並把信息保存在buf緩衝區內。
2) 得到文件信息
函數原型:
#include <sys/stat.h>
int fstat(int fildes, struct stat *buf);
int lstat(const char *restrict path, struct stat *restrict buf);
函數功能:
fstat()函數得到一個已經打開的文件的信息,並存入緩衝區buf內;lstat()函數得到一個符號連接的文件的信息,並保存在buf緩衝區內。
3) 檢查文件的權限
函數原型:
#include <unistd.h>
int access(const char *path, int amode);函數功能:
函數功能:
該函數檢查路徑下的文件權限,若權限正確返回0,不然返回-1。
5.7 可配置文件變量
1) 改變文件權限變量
函數原型:
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fildes,, mode_t mode);
函數功能:
chmod()和fchmod()函數改變路徑下的文件權限變量mode,若修改正確,返回0,不然返回-1。不一樣的是chmod()是在制定的文件上進行操做,而fchmod()則對已打開的文件進行操做。
2) 更改文件的用戶ID和組ID
函數原型:
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fildes, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
函數功能:
除了所引用的文件時符號連接外,這三個函數的操做類似。在符號連接的狀況下,lchown()更改符號連接自己的全部者,而不是該符號連接所指向的文件。
3) 更改文件訪問和修改時間
函數原型:
#include <utime.h>
int utime(const char *path, const struct utimbuf *times);
函數功能:
此函數使用的數據結構是:
struct utimbuf{
time_t actime;
time_t modtime;
}
調用函數後獲得文件訪問和修改的日曆時間。
4) 文件截短
函數原型:
#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int fildes, off_t length);
函數功能:
這兩個函數將把現有的文件長度階段爲length字節。若是該文件之前的長度大於length,則超過length之外的數據就再也不能訪問了。函數ftruncate()是POSIX.1的組成部分,truncate()函數式POSIX.1功能的XSI擴展部分。
5) 文件路徑名變量配置
函數原型:
#include <unistd.h>
long fpathconf(int fildes, int name);
long pathconf(const char *path, int name);
函數功能:
配置文件路徑名變量。
六 輸入與輸出源語
6.1 管道
1) 建立內進程通道
函數原型:
#include<unistd.h>
int pipe(int filedw[2]);
函數功能:
該函數建立一個管道而且建立兩個文件描述符,一個是fildes[0],一個是fildes[1],它們分別指的是‘讀’與‘寫’的管道端。
6.2 文件描述符控制
1) 複製一個打開文件描述符
函數原型:
#include<unistd.h>
int dup(int fildes);
int dup2(int fileds,int fileds2);
函數功能:
這兩個函數爲fcntl()服務提供了兩個選擇的接口,用到了F_DUPFD命令。
fid = dup(fildes);至關於fid = fcntl(fildes, F_DUPFD, 0);
fid = dup2(fildes, fildes2);至關於close(fildes2);fid = fcntl(fildes, F_DUPFD, fildes2);
6.3 撤除文件描述符
1) 關閉一個文件
函數原型:
#include<unistd.h>
int close(int fildes);
函數功能:
關閉一個文件。關閉一個文件時還會釋放該進程加載該文件上的全部記錄鎖。當一個進程終止時,內核自動關閉它全部打開的文件。
6.4 輸入和輸出
1) 文件讀
函數原型:
#include<unistd.h>
ssize_t read(int fildes,void *buf,size_t nbyte);
函數功能:
從打開文件中讀數據。如read成功,則返回讀到的字節數。若是已到達文件結尾,則返回0。
2) 文件寫
函數原型:
#include<unistd.h>
ssize_t write(int fildes,const void *buf,size_t nbyte);
函數功能:
該函數向打開的文件寫數據。
6.5 一個文件的控制操做
1) 文件控制操做的數據定義
頭文件<fcnt1.h>爲fcntl()和open()定義了一下的要求和參數:
fcntl()的_cmd值
常量 |
描述 |
F_DUPFD |
複製文件描述符fileds |
F_GETFD |
對應於filedes的文件描述符標誌做爲函數值返回 |
F_GETLK |
判斷由flockptr所描述的鎖是否會被另一把鎖所排斥 |
F_SETFD |
對於filedes設置文件描述符標誌 |
F_GETFL |
對應於filedes的文件狀態標誌做爲函數值返回 |
F_SETFL |
將文件狀態標誌設置爲第三個參數的值(即爲整形值) |
F_SETLK |
設置由flockptr所描述的鎖 |
F_SETLKW |
這是F_SETLK的阻塞版本(w表示等待(wait)) |
F_GETOWN |
取當前接收SIGIO和SIGURG信號的進程ID或進程組ID |
F_SETOWN |
設置接收SIGIO和SIGURG信號的進程ID或進程組ID |
2) 文件控制
函數原型:
#include <sys/types.h>
#inclued<unistd.h>
#include<fcntl.h>
int fcntl(int fildes,int cmd,…);
函數功能:
fcntl()爲打開的文件提供了一系列控制,參數fildes是一個文件描述符。cmd決定了控制的內容。
fcntl()有5種功能:一、複製一個現有的描述符(cmd=F_DUPFD)二、得到/設置文件描述符標記(cmd=F_GETFD或F_SETFD)三、得到/設置文件狀態標誌(cmd=F_GETFL或F_SETOWN)四、得到/設置一部I/O全部權(cmd=F_GETOWN或F_SETOWN)五、得到/設置記錄鎖(cmd=F_GETLK、F_SETLK或F_SETLKW)。
3) 讀/寫文件偏移量的從新定位
函數原型:
#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fildes,off_t offset,int whence);
函數功能:
lseek()爲fildes所指定的文件從新設置偏移量。
若whence是SEEK_SET,則將該文件的偏移量設置爲距文件開始處offset個字節。
若whence是SEEK_CUR,則將該文件的偏移量設置爲其當前值加offset,offset可爲正或負。
若whence是SEEK_END,則將該文件的偏移量設置爲文件長度加offset,offset可爲正或負。
若lseek()成功執行,返回新的文件偏移量。
6.6 文件同步
1) 文件的狀態同步
函數原型:
#include<unistd.h>
int fsync(int fildes);
函數功能:
該函數用來暗示全部的文件描述數據被傳輸到了存儲設備上。該函數值對由文件描述符filedes指定的單一文件起做用,而且帶寫磁盤操做結束,而後返回。
2) 文件數據的同步
函數原型:
#include<unistd.h>
int fdatasync(int fildes);
函數功能:
該函數迫使當前全部排隊的I/O操做進入同步 I/O狀態。該函數相似於函數fsync(),但它隻影響文件的數據部分。
6.7 異步輸入與輸出
1) 異步輸入與輸出的數據定義
頭文件<aio.h>能使<sys/types.h>,<signal.h>,<time.h>和<fcntl.h>中的符號可見。
異步I/O控制塊
異步I/O控制塊結構aiocb在許多異步I/O接口中使用,它在<aio.h>中定義。
2) 異步讀
函數原型:
#include<aio.h>
int aio_read (struct aiocb *aiocbp);
函數功能:
aiocbp->io_nbytes,表示讀的字節數;aiocbp->aio_fildes,表示讀的文件;aiocbp->aio_buf,表示讀到的緩衝區。
3) 異步寫
函數原型:
#include<aio.h>
int aio_write(struct aiocb *aiocbp);
函數功能:
參數表示同上。
4) 列出直接I/O
函數原型:
#include<aio.h>
int lio_listio(int mode,struct aiocb *const list[],int nent,struct sigevent *sig);
函數功能:
該函數容許用一個函數調用初始化一個I/O請求列表。
5) 獲得異步I/O操做的錯誤狀態
函數原型:
#include<aio.h>
int aio_error(const struct aiocb *aiocbp);
函數功能:
該函數返回aiocbp指向的結構所表示的錯誤狀態。
6) 獲得異步I/O操做的返回狀態
函從數原型:
#include<aio.h>
ssize_t aio_return(struct aiocb *aiocbp);
函數功能:
獲得異步I/O操做的返回狀態。
7) 刪除異步I/O請求
函數原型:
#include<aio.h>
int aio_cancel (int fildes,struct aiocb *aiocbp);
函數功能:
參數fildes是文件描述符,參數aiocbp指向異步I/O控制塊上的請求刪除部分。
8) 等待異步I/O請求
函數原型:
#include<aio.h>
int aio_suspend(const struct aiocb *const list[],int nent,const struct timespec *timeout);
函數功能:
標準定義該函數掛起調用進程直到至少一個list指向的異步I/O操做完成,或者一個信號中斷了一個函數,或者超時了(timeout指定)。
9) 異步文件同步化
函數原型:
#include<aio.h>
int aio_fsync(int op,struct aiocb *aiocbp);
函數功能:
該函數迫使全部與(參數aiocbp指向的)結構aiocb中aio_fildes所指定的文件相關異步I/O操做進入同步狀態。
七 設備和麪向類的函數
7.1 基本的終端接口
1) 接口特性
●當一個終端文件被打開,一般它將引發進程等待直到鏈接被創建。
●進程組一個終端能夠具備與它相關的前臺進程組,它發揮特定的角色,後面會講到。
●控制終端
●終端存取控制
●輸入操做和讀進程
●規範的輸入操做
●非規範模式的輸入操做
●寫數據和輸出處理
●特殊的符號(INTR,QUIT,ERASE,KILL…)
●modem斷掉鏈接
●關閉終端設備文件
2) 可設置的參數
●termios機構
該結構在<termios.h>中定義,在控制特定的終端I/O特性中要用到。
●輸入模式
termios c_iflag
標記名 |
描述 |
BRKINT |
信號中斷 |
ICRNL |
輸入時將CR映射到NL |
IGNBRK |
忽略中斷狀態 |
IGNCR |
忽略CR |
IGNPAR |
忽略奇偶錯誤 |
INLCR |
輸入時將NL映射到CR |
INPCK |
輸入奇偶校驗使能 |
ISTRIP |
Strip字符 |
IXOFF |
開始/中止輸入控制使能 |
IXON |
開始/中止輸出控制使能 |
PARMRK |
產生奇偶錯誤 |
●輸出模式
termios c_oflag
標記名 |
描述 |
BSDLY |
退格延遲屏蔽 |
CMSPAR |
標記或空奇偶性 |
CRDLY |
CR延遲屏蔽 |
FFDLY |
換頁延遲屏蔽 |
NLDLY |
NL延遲屏蔽 |
OCRNL |
將輸出的CR轉換爲NL |
OFILL |
對於延遲使用填充符 |
OLCUC |
將輸出的小寫字符轉換爲大寫字符 |
ONLCR |
將NL轉化爲CR-NL |
ONLRET |
NL執行CR功能 |
ONOCR |
在0列不輸出CR |
ONOEOT |
在輸出中刪除EOT(^D)字符 |
OPOST |
執行輸出處理 |
OXTABS |
將製表符擴充爲空格 |
TABDLY |
水平製表符延遲屏蔽 |
VTDLY |
垂直製表符延遲屏蔽 |
●控制模式
termios c_cflag
標記名 |
描述 |
CBAUDEXT |
擴充的波特率 |
CREAD |
啓用接收裝置 |
CSIZE |
字符大小屏蔽 |
CS5 |
5位 |
CS6 |
6位 |
CS7 |
7位 |
CS8 |
8位 |
CSTOPB |
送兩個中止位,不然爲1位 |
HUPCL |
在最後的關閉中掛起 |
PARENB |
奇校驗使能 |
PARODD |
奇校驗或偶校驗 |
●本地模式
termios c_lflag 值
標記名 |
描述 |
ECHO |
進行回送 |
ECHOE |
可見擦除符 |
ECHOK |
回送kill符 |
ECHONL |
響應’/n’ |
ICANON |
規範輸入 |
IEXTEN |
啓用擴充的輸入字符處理 |
ISIG |
啓用中斷產生的信號 |
NOFLSH |
中斷,中止或掛起後關掉flush |
TOSTOP |
爲後臺輸出發送SIGTTOU |
●特殊的控制字符
這些特殊的控制字符值在隊列c_cc中定義,分爲規範和非規範兩種模式。
●波特率值
3) 波特率函數
函數原型:
#include<termios.h>
speed_t cfgetospeed(const struct termios *termios_p);
int cfsetospeed(struct termios *termios_p,speed_t speed);
speed_t cfgetispeed(const struct termios *termios_p);
int cfsetispeed(struct termios *termios_p,speed_t speed);
函數功能:
以上這些接口被用來在termios結構得到和設定輸入與輸出的波特率值。
7.2 基本的終端接口控制函數
1) 得到並設定狀態
函數原型:
#include<termios.h>
int tcgetattr(int fildes,struct termios *termios_p);
int tcsetattr(int fildes,int optional_actions,const struct termios * termios_p);
函數功能:
tcgetattr()得到fildes所肯定的文件的參數並將其存儲在t_erops_p所指向的結構中;tcsetattr()將設置參數。
2) 行控制函數
函數原型:
#include<termios.h>
int tcsendbreak(int fildes,int duration);
int tcdrain(int fildes);
int tcflush(int fildes,int queue_selector);
int tcflow(int fildes,int action)’
函數功能:
若是終端使用異步連續數據傳輸,tcsendbreak()引發在一段時間內連續的‘0’位傳輸;tcdrain()等待直到輸出傳輸完畢;tcflush()函數刷清輸入緩衝區或輸出緩衝區;tcflow()用於對輸入和輸出流控制進行控制。
3) 得到和設置終端屬性
函數原型:
#include<termios.h>
int tcgetattr(int filedes, stuct termios *termptr);
int tcsetattr(int filedes, int opt, const struct termios *termptr);
函數功能:
這兩個函數都有一個指向termios結構的指針做爲其參數,它們返回當前終端的屬性,或者設置該終端的屬性。
八 基於C語言的服務
8.1 C語言輸入/輸出函數
1) 設置程序環境
函數原型:
#include <locale.h>
char *setlocale(int category, const char *locale);
函數功能:
該函數設置程序運行環境。
2) 映射一個流指針到一個文件描述符
函數原型:
#include<stdio.h>
int fileno(FILE *stream);
函數功能:
每一個標準I/O流都有一個與其相關聯的文件描述符,能夠對一個流調用fileno函數以得到其描述符。該函數是POSIX.1支持的擴展。
3) 根據一個文件描述符打開一個流
函數原型:
#include<stdio.h>
FILE *fdopen(int fildes,const char *type);
函數功能:
該函數獲取一個現有的文件描述符(咱們可能從open,dup,dup2,fcntl,pipe,socket,socketpair或accept函數獲得此文件描述符),並使一個標準的I/O流與該描述符相結合。該函數經常使用於由建立管道和網絡通訊通道函數返回的描述符。
4) 其餘文件類型函數之間的相互做用
一個單一的文件描述說明能夠經過流和文件描述符訪問,流或者是文件描述符被稱做位打開文件的句柄,一個打開文件說明能夠有多個句柄。句柄能夠在不影響重要的打開文件說明的狀況下被建立和刪除,建立如fcntl(),dup(),fdopen(),fileno(),fork();刪除如fclose(),close()。
a) fopen()隨着open()的調用分配描述符,基礎函數爲open()。
b) fclose():該函數完成在與FILE流相關的,對文件描述符的close()功能。
c) freopen():具備fclose()和fopen()的特色。
d) fflush():若是流可寫或者緩存數據尚未寫入文件時,該函數標記下基礎文件st_ctime和st_mtime的值。
e) fgetc(),fgets(),fread(),getc(),getchar(),gets(),scanf(),fscanf():這些函數標記更新的st_atime值。 基礎函數是read()和lseek()。
f) fputc(),fputs(),fwrite(),putc(),putchar(),puts(),printf(),fprintf():從以上任一個函數的成功執行到下一個調用(在同一個流中的fflush()或fclose()或exit()或abort()),記下更新的st_ctime和st_mtime值。基礎函數是write()和 lseek()。
g) fseek(),rewind():若是流可寫或者緩存數據尚未寫入文件時,該函數標記下文件更新的st_ctime和st_mtime值。基礎函數是lseek()和write()。
h) perror():記下與標準錯誤流相關的文件。
i) tmpfile():fopen()執行後爲文件分配文件描述符。
j) ftell(): 基礎文件是lseek()。執行fflush()後執行該函數的結果與執行fflush前執行該函數的結果相同。
k) 報錯
l) exit(),abort():exit()終止進程的時候要關閉流, abort()只終止進程對流沒有影響。
5) 文件操做remove()函數
該函數和unlink()函數的功能同樣。
8.2 其餘的C函數
1) 非局部跳轉
函數原型:
#include<setjmp.h>
int sigsetjmp(sigjmp_buf env,int savemask);
void siglongjmp(sigjmp_buf env,int val);
函數功能:
sigsetjmp()宏要與標準中setjmp()宏的定義一致,若是參數savemask不爲「0」,sigsetjmp()就要保存當前的信號標記做爲調用環境的一部分。siglongjmp()同理。
2) 設置時間域
函數原型:
#include<time.h>
void tzset(void);
函數功能:
該函數用環境變量TZ的值來設定時間變化信息。
九 系統數據庫
9.1 系統數據庫
本章描述了兩個數據庫:組數據庫和用戶數據庫。
組數據庫包括的信息有:組名,組的數字ID,組中的用戶列表;
用戶數據庫包含的信息有:用戶名,用戶的數字ID,組的數字ID,初始化的工做目錄和初始化的用戶程序。
9.2 數據庫的訪問
1) 組數據庫的訪問
函數原型:
#include<sys/type.h>
#include<grp.h>
struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);
函數功能:
getgrid()和getgrnam()返回指針,它指向一個struct group類型的對象,包含了組數據庫的入口。
2) 用戶數據庫的訪問
函數原型:
#include<sys/types.h>
#include <pwd.h>
struct paswd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
函數功能:
getpwuid()和getpwnam()返回一個指針,指向struct passwd類型的一個對象,它包含了用戶數據庫的入口。
十 信號量
10.1信號量特徵
頭文件<semaphore.h>定義了sem_t類型,它用於信號量操做中。sem_t表明了信號量,用文件描述符可以實現這些信號量,應用程序可以打開至少{OPEN_MAX}這麼多的文件和信號量。標準中,頭文件<semaphore.h>能使頭文件<sys/types.h>和<fcntl.h>中的符號可見。
爲了得到共享資源,進程須要執行下列操做:
(1) 測試控制該資源的信號量
(2) 若此信號量的值爲正,則進程可使用該資源。進程可使用該資源。進程將信號量只減1,表示它使用了一個資源單位。
(3) 若此信號量的值爲0,則進程進入休眠狀態,直至信號量值大於0.進程被喚醒後,它返回至第(1)步。
10.2信號量函數
1) 初始化一個未命名的信號量
函數原型:
#inxlude<semaphore.h>
int sem_init(sem_t *sem,int pshared,unsigned int value);
函數功能:
該函數被用來初始化sem引用的未命名信號量。在成功調用該函數之後,在接下來的sem_wait(),sem_trywait(),sem_post(),sem_destroy()的調用中,該信號量將被用到。若是參數pshared不爲零,信號量將在進程中被共享,任何能夠訪問信號量sem的進程均可以使用sem。只有sem能被用來進行同步。若是參數pshared爲零,則結構不肯定。若是標準中未定義,能夠由執行者來支持該函數。
2) 刪除一個未命名信號量
函數原型:
#include <semaphore.h>
int sem_destroy(sem_t *sem);
函數功能:
該函數用來刪除sem引用的未命名信號量,只有在sem_init()中建立的信號量才能被該函數刪除。
3) 初始化/打開一個命名信號量
函數原型:
#include<semaphore.h>
sem_t *sem_open(const char *name,int oflag,…);
函數功能:
該函數在進程和命名信號量之間建立一個連接。接着調用帶有信號量名name的該函數,進程引用與name相關的信號量。該信號量在一些函數的調用中用到,如sem_wait(),sem_trywait(),sem_post,和sem_close()。信號量一直可用知道調用函數sem_close(),_exit,exec()關閉它。參數oflag控制是否信號量由sem_open()建立或者僅被它訪問。
4) 關閉一個命名信號量
函數原型:
#include<semphore.h>
int sem_close(sem_t *sem);
函數功能:
該函數用來提示調用進程已經完成使用sem所指明的信號量。該函數釋放系統資源,這些資源被擁有該信號量的進程佔有。
5) 移走一個命名信號量
函數原型:
#include<semaphore.h>
int sem_unlink(const char *name);
函數功能:
該函數將移走被字符串name命名的信號量。若是該信號量當前被其餘進程引用,則該函數對信號量狀態沒有影響。若是一個和更多的進程打開了該信號量,則銷燬該信號量被延遲知道全部的信號量被sem_close(),_exit(),exec關閉。
6) 鎖定一個信號量
函數原型:
#include<semaphore.h>
int sem_wait (sem_t*sem);
int sem_trywait(sem_t *sem);
函數功能:
sem_wait()鎖定sem引用的一個信號量,對該信號進行鎖定操做。若是信號量爲’0’,調用進程將不會返回直到鎖定了這個信號量或者被一個信號中斷。Sem_trywait()只能在信號量當前沒被鎖定的狀況下鎖定它,不然將不會鎖定信號量。成功返回,信號量的狀態將被鎖定直到sem_post()被調用而且成功返回。
7) 解鎖一個信號量
函數原型:
#include<semaphore.h>
int sem_post(sem_t *sem);
函數功能:
該函數經過對一個信號量的解鎖操做解鎖一個被sem引用的信號量。若是該操做的結果,信號量值爲正數,則沒有進程被鎖定來等待一個信號量解鎖,信號量值是單一的增長。若是信號量值爲’0’,則進程被鎖定來等待一個信號量被容許從sem_wait()成功返回。
8) 取得一個信號量值
函數原型:
#include<semaphore.h>
int sem_getvalue(sem_t *sem,int *sval);
函數功能:
該函數更新參數sval所引用的位置,在不改變信號量狀態的狀況下獲得信號量值。更新的值表明了一個確切的值,它產生在調用中的一個不定時刻,但它返回給調用進程是不必定須要信號量的肯定值。若是sem被鎖定,則sem_getvalue()返回的值爲0,或者負數,它表明了等待信號量的進程數。
十一 內存管理
該章節描述了進程內存鎖定,內存映象文件和共享內存工具。
內存鎖定和內存映象文件以頁的方式定義。執行者能夠據據頁大小的規範限制和排列鎖定和映象範圍。頁的大小,以字節爲單位,是一個可配置系統變量。默認爲1B。
內存鎖定保證了一部分地址空間的駐留。
11.1內存鎖定函數
1) 鎖定/解鎖進程地址空間
函數原型:
#include<sys/mman.h>
int mlockall(int flags);
int munlockall(void);
函數功能:
mlockall()使進程地址空間所映射的全部頁面成爲內存駐留區,直到解鎖或者進程退出或者execs另外一個進程映象。參數flags決定了是否被鎖定的頁面是由當前,(未來,或者二者都是)的進程地址空間映射的。Munlockall()解鎖當前全部的進程地址空間映射頁面。全部映射到進程地址空間的頁面,調用了該函數,將不會被鎖定,除非有中斷調用mlockall()肯定MCL_CURRENT,或者併發調用mlockall()肯定MCL_CURRENT。
2) 鎖定/解鎖一連續的地址空間
函數原型:
#include<sys/mman.h>
int mlock(const void *addr,size_t len);
int munlock(const void *addr,size_t len);
函數功能:
mlock()使一個範圍的進程地址空間成爲內存駐留區(addr決定了空間的起始地址,len決定了空間長度)直到解鎖或者進程退出或者execs另外一個進程映象;munlock()解鎖一個範圍的進程地址空間(addr決定了空間的起始地址,len決定了空間長度);
11.2內存映象函數
1) 映象進程地址到一個內存目標
函數原型:
#include<sys/mman.h>
void *mmap(void *addr,size_t len,int prot,int flags,int fildes,off_t off);
函數功能:
該函數在一個進程的地址空間和內存對象間建立一個映射,調用格式如:pa=mmap(addr,len,prot,flags,fildes,off);pa表明進程進程地址空間的地址,由執行者定義(addr和flags),len表示空間長度,fildes表明內存對象,off表示偏移量。函數成功調用返回pa,空間地址範開始與pa,長度爲連續的len個字節;內存對象開始與off,長度爲len字節。參數prot決定了讀,寫,執行,或一些映射數據的訪問活動的集合。
2) 取消之前映射地址的映射關係
函數原型:
#include<sys/mman.h>
int munmap(void *addr,size_t len);
函數功能:
該函數移去任何包含有進程地址空間的頁面的映射關係,該進程地址空間起始於addr,長度爲len字節。
3) 改變內存保護
函數原型:
#include <sys/mman.h>
int mprotet(const void *addr,size_t len,int prot);
函數功能:
該函數更改訪問的保護活動,由參數prot肯定。訪問對象是一部分進程地址空間,起始於addr,長度爲len字節。
4) 內存對象同步
函數原型:
#inxlude<sys/mman.h>
int msync(void *addr,size_t len,int flags);
函數功能:
該函數將全部更改了的數據寫到擁有存儲的地方,它包含了進程地址空間,起始於addr,長度爲len字節。若是沒有這樣的存儲區域存在,則給函數沒有做用。該函數須保證寫操做的完成符合所定義的同步I/O數據的一致完成性。參數flags肯定了寫的同步/異步性。
11.3共享內存函數
1) 打開一個共享內存對象
函數原型:
include<sys/mman.h>
int shm_open(const *name,int oflag,mode_t mode);
函數功能:
該函數在共享內存對象和文件描述符之間建立了一個鏈接。它建立了一個打開文件描述涉及到共享內存對象,而且建立了一個文件描述符指向這個打開文件描述。這個文件描述符可悲其餘函數用來指向共享內存對象,參數name指向共享內存對象名。如函數調用成功,則返回一個共享內存的文件。文件狀態和文件訪問模式根據oflag的值來設定。
2) 移去一個共享內存對象
函數原型:
#include <sys/mman.h>
int shm_unlink(const char *name);
函數功能:
該函數移去由name命名的共享內存對象。若是一個或者多個對共內存的引用在對象斷開鏈接的同時退出的話,這個名字應在shim_unlink()返回以前移走,可是對內存對象的移走須延遲到全部對共享內存對打開和映射引用被移去後。
十二 執行調度
12.1調度參數
一個調度參數結構sched_param包括了調度策略所支持的執行者所須要的調度參數,它在頭文件<sched.h>中定義。執行者可根據規對該結構進行擴展。
12.2調度策略
該章所闡述的調度術語是從概念模型上定義的,它包含了一組進程列表。這個模型只討論了可運行進程的處理器調度,可是它注重了在其餘資源考慮處處理器調度策略的狀況下,加強了實時操做的可預見性。在這裏,概念上講是一個進程列表一個策略。調度策略的目的就是對這一組列表定義容許的操做(例如,在進程列表之中和之間移動進程)。每個進程應由相關的調度策略和優先級,於每個策略相關的是一個優先級範圍。
1) SCHED_FIFO
該策略是一種先進先出的調度策略。若是正在執行的進程是被搶佔的進程,則他應該在進程列表頭;若是一個鎖定的進程變成可執行進程,它就進入進程列表尾;當執行進程調用sched_setscheduler(),則函數中肯定的進程被改成指定的策略;當執行進程調用sced_setparam(),進程的優先級根據參數param被修改,若是改進程是正在執行和可執行,則它將進入進程列表尾;當正在執行的進程調用seced_yield(),進程進入列表尾。
2) SCHED_RR
該策略與上面的策略不一樣的是,若是執行中檢測到進程的執行時間已經到達或超過了sched_rr_get_interval()所返回的時間片,進程就進入列表尾而且進程列表頭移動一個進程進入執行狀態。
3) SCHED_OTHER
12.3進程調度函數
1) 設置調度參數
函數原型:
#include<sched.h>
int sched_setparam(pid_t pid,const struct sched_param *param);
函數功能:
pid指明瞭進程,param指向了sched_param結構,該結構設定了進程的調度參數。若是pid=0,調度參數爲調用進程設定。若是pid指定的進程的優先級高於正在指向的進程而且該進程可執行,則搶佔如今正在運行的進程。若是當前的策略不是前面將的三種方式,則由執行者定義。
2) 取得調度參數
函數原型:
#include<sched.h>
int sched_getparam(pid_t,struct sched_param *param);
函數功能:
該函數返回調度參數,若是一個pid進程退出而且調用進程容許,則ID等於pid的進程返回其調用參數。若是pid=0,則返回調用進程的調度參數。
3) 設置調度策略和調度參數
函數原型:
#include<sched.h>
int sched_setscheduler(pid_t pid,int policy,const struct sched_param *param);
函數功能:
該函數設置進程的調度策略和調度參數,pid表示進程,policy指明策略,參數param指向的sched_param結構指明瞭調度參數。執行者可要求請求進程能容許設定本身或其餘進程的調度參數。
4) 取得調度策略
函數原型:
#include<sched.h>
int sched_getscheduler(pid_t pid);
函數功能:
該函數返回pid進程的調度策略,其返回值在頭文件<sched.h>中定義。
5) 放棄處理器
函數原型:
#include<sched.h>
int sched_yield(void);
函數功能:
該函數迫使正在執行進程放棄處理器直到從新進入進程列表頭。
6) 得到調度參數範圍
函數原型:
#incude<sched.h>
int sched_get_priority_max(int policy);
int sched get_priority min(int policy);
int sched_rr_get_interval(pid_t pid, struct timespec *interval);
函數功能:
sched_get_priority_max()和sched_get_priority_min()返回policy調度策略相應的最大最小值。Sched_rr_get_interval()更新interval參數引用的timespec結構,包含了當前進程執行的時間限制。
十三 時鐘和定時器
13.1時鐘和定時器的數據定義
頭文件<time.h>定義了時間設備用到的類型和主要常量。
1) 時間值的規格結構
一個時間值結構timespec肯定了單一時間值而且包括瞭如下值:
成員類型 |
成員名 |
描述 |
time_t |
tv_sec |
seconds |
long |
tv_nsec |
nanosenconds |
執行者可對他作擴展,tv_nsed成員要大於等於零時纔可用。
時間值結構itimerspec肯定了一個初始化的定時器和各進程定時器函數用到的重複間隔。結構包括:
成員類型 |
成員名 |
描述 |
Struct timespec |
It_interval |
Timer period |
Struct timespec |
It_value |
Timer expiration |
執行者也能夠對其作擴展。
2) 定時器活動喚醒控制塊
爲了使完成支持實時信號擴展功能,各進程定時器被建立經過排列實時擴展信號來通知定時器超時的進程。Sigevent結構在頭文件<signal.h>中定義,用來建立一個這樣的定時器。
3) 類型定義
在<sys/types.h>中定義。
4) 主要常量
在<time.h>中定義:
CLOCK_REALTIME 系統範圍的實時時鐘標誌
TIMER_ABSTIME flag指定的時間對於時鐘是「徹底」的
13.2時鐘和定時器函數
1) 時鐘
函數原型:
#include<time.h>
int clock_settime(clockid_t clock_id,const struct timespec *tp);
int coock_gettime(clockid_t clock_id,struct timespec*tp);
int clock_getres(clockid_t clock_id,struct timespec *res);
函數功能:
clock_settime()設置特定時鐘,clock_id,到tp指定的值。
Clock_gettime()返回當前的tp值,即時鐘,clock_id;
clock_getres()能夠獲得時鐘的肯定值,該值由執行者定義而不禁進程設定。若是res不爲空,則該值被存儲在res指向的地方,若是res爲空,則時鐘決定值不被返回。
2) 建立一個總進程定時器
函數原型:
#include<signal>
#include<time.h>
int timer_create(clockid_t clock_id,struct sigevent *evp,timer_t *timerid);
函數功能:
timer_create()建立一個總進程定時器,用來指明時鐘,clock_id,做爲計時基礎。該函數在timerid指向的地方返回一個timer_t類型的定時器ID,該ID在調用進程中必須是惟一的直到定時器被刪除。參數evp若是不爲空,則指向一個sigevent結構,定義了定時器超時時出現的異步通知。結構中sigev_notify爲SIGEV_SIGNAL時,結構就包括了超時時送往進程的信號數和應用數據;若是sigev_notify爲SIGEV_NONE,則不發送任何通知;sigev_notify其餘的值由完成者自行定義。總進程的定時器不被其子進程經過fork()繼承,它應該被exec撤銷。
3) 刪除一個總進程定時器
函數原型:
#include<time.h>
int timer_delete(time_t timerid);
函數功能:
該函數刪除一個指定的定時器,timerid,該定時器是在之前的timer_create()中建立的。
4) 總進程定時器
函數原型:
#include<time.h>
int timer_settime(timer_t timerid,int flags,const struct itimerspec *value,struct itimerspec *ovalue);
int timer_gettime(timer_t timerid,struct itimerspec *value);
int timer_getoverrun(timer_t timerid);
函數功能:
timer_settime()設置時間直到下一個timerid指定的定時器終止。若是該函數調用時定時器已經被裝備,該調用則重置時間直到value肯定的下一次終止。若是value的it_value成員爲零,定時器被解除。若是flag沒有設定爲TIMER_ABSTIME,則定時器從調用開始在it_value十億分之一秒內超時;若是設定爲TIMER_ABSTIME,該函數表現爲時間直到下一次超時被設定爲it_value指定的絕對時間和與timerid相聯的時鐘值的差值。定時器的再裝由value的it_interval成員值來設定。若是參數ovalue不爲空,該函數被存儲在ovalue引用的地方。該函數要存儲時間累計值直到timerid指定的定時器終止或重裝定時器值到value參數。在任一時刻,僅有一個單一信號被派了在指定的定時器的進程中。若是支持實時信號擴展,timer_getoverrun()返回定時器終止的溢出值。
5) 高度睡眠
函數原型:
#include<time.h>
int nanosleep(const struct timespec *rqtp,struct timespec *rmtp);
函數功能:
該函數使當前執行的進程掛起直到參數rptp指定的時間間隔到達或者信號被送到調用進程而且其行爲就是喚醒信號跟蹤功能或者使終止進程。掛起時間也許要比要求時間長是由於參數值向上舍入成一個整數或者是由於系統對其餘活動的調度。可是除非被信號打斷,掛起時間不會少於tqtp值,這是系統時鐘,CLOCK_REALTIME測量的。
十四 消息傳遞
14.1消息隊列的數據定義
1) 數據結構
頭文件< mqueue.h>定義瞭如下執行者定義的類型:
mqd_t :用於消息隊列描述符
頭文件< mqueue.h>定義瞭如下執行者定義的結構:
mq_attr用來設定消息隊列參數。
struct sigevent結構包含了至少如下的成員:
類型 |
成員名 |
描述 |
long |
mq_flags |
消息隊列標誌 |
long |
mq_maxmsg |
最大消息數 |
long |
mq_msgsize |
消息的最大長度 |
long |
mq_curmsgs |
當前排列的消息數 |
14.2消息傳遞函數
1) 打開消息隊列
函數原型:
#include<mqueue.h>
mqd_t mq_open(const char *name,int oflag,…);
函數功能:
該函數在進程和消息隊列之間創建鏈接。它建立了一個消息隊列描述符指向消息隊列。參數oflag請求對消息隊列發送或接收所需信息。若是調用進程認可對相應保護文件的讀寫請求,則對接收或發送消息的請求容許被經過。
2) 關閉一個消息隊列
函數原型:
#include<mqueue.h>
int mq_close(mqd_t mqdes);
函數功能:
該函數撤銷消息隊列描述符(mqdes)和消息隊列之間的關係。若是進程成功的配屬了mqdes表示的消息隊列通知請求,則這個配屬關係被撤銷,該消息隊列可用於其餘進程來配屬通知。
3) 移去一個消息隊列
函數原型:
#include<mqueue.h>
int mq_unlink(const char *name);
函數功能:
該函數移去路徑名name指向的消息隊列。若是該調用成功,而且flag沒有設爲O_CREATE,則mq_open()對於同一個name將會失敗。全部對該隊列的引用撤銷後,該隊列才能被關閉。該函數調用不會被阻塞指定全部的引用被關閉。
4) 發送一個消息到消息隊列
函數原型:
#include<mqueue.h>
int mq_send(mqd_t mqdes,const char *msg_ptr,size_t mag_len,unsigned int msg_prio);
函數功能:
該函數添加參數msg_ptr指向的消息到mqdes指定的消息隊列中去。參數msg_len表示消息長度,以字節爲單位,該參數應小於等於消息隊列的mq_msgsize參數,不然調用失敗。若是消息隊列沒有滿,則該函數的功能就是插入消息到消息隊列的指定位置,這個位置郵msg_prio參數指定。msg_prio大者先插入隊列,msg_prio的值應小於等於{MQ_PRIO_MAX}。若是消息已滿而且O_NONBLOCK沒有設定,該函數阻塞一直到空間可用或者mq_send()被信號中斷。若是空間可用時,多於一個進程在等待發送則按優先級,等待最久的進程先發送它的信息。若是O_NONBLOCK被設定,而且隊列已滿,則函數返回error。
5) 從消息隊列接受一條消息
函數原型:
#include<mqueue.h>
ssize_t mq_receive(mqd_t mqdes,char *msg_ptr,size_t msg_len,unsigned int *msg_prio);
函數功能:
該函數接受mqdes肯定的消息隊列中最久優先級最高的消息,對參數值的限制同上。所選消息從隊列移出,複製到msa_ptr指向的緩衝區。若是參數msg_prio不爲空,則指定消息被存儲在msa_prio所引用的地方。若是消息隊列爲空,而且O_NONBLODK沒有設定,該函數阻塞直到消息排列入隊列中或者該函數被信號中斷。當有多個進程在消息到達隊列後請求接受,則優先級原則與上相同。
6) 通知一個進程隊列中的一條信息可用
函數原型:
#include<mqueue.h>
int mq_notify(mqd_t mqdes,const struct sigevent *notification);
函數功能:
若是參數notification不爲空,函數記錄下調用進程被通知空的消息隊列(由消息隊列描述符mqdes相聯)中有一條消息到來。當消息隊列從空到非空時,一條通知消息將發送到進程中,在任一時刻,只有一個通知消息被一個消息隊列記錄。若是notifiction爲空而且進程當前被指定的隊列記錄,則已存在的記錄被移去。
7) 設置消息隊列參數
函數原型:
#include <mqueue.h>
int mq_setattr(mqd_t mqdes,const struct mq_attr *mqstat,struct mq_attr *omqstat);
函數功能:
該函數用來設置與mqdes指定的消息隊列相關的參數。mq_attr結構中的mq_maxmsg,mq_magsize,mq_curmsgs成員被mq_setattr()忽略。若是omqstat爲非空,則該函數被存儲,由omqstat指明存儲位置。
8) 獲得消息隊列參數
函數原型:
#include<mqueue.h>
int mq_getattr(mqd_t mqdes,struct mq_attr *mqstat);
函數功能:
該函數用來取得狀態信息和與mqdes消息隊列相關的參數。
十五 互斥量
15.1互斥量屬性
1) 初始化互斥量屬性
函數原型:
#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
函數功能:
pthread_mutexattr_init()函數將用默認值初始化互斥屬性對象attr來定義的全部屬性,能夠用宏PTHREAD_MUTEX_INITIALIZER來靜態的初始化鎖。若是初始化成功,返回0,不然返回error。
2) 刪除互斥量屬性
函數原型:
#include <pthread.h>
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
函數功能:
pthread_mutexattr_ destroy()函數刪除互斥屬性對象attr定義的全部屬性。
3) 得到和設置互斥量屬性
函數原型:
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *restrict attr, int *restrict protocol);
int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);
函數功能:
pthread_mutexattr_getprotocol()函數得到互斥屬性對象的協議屬性; pthread_mutexattr_setprotocol()函數設置互斥屬性對象的協議屬性,設置是否支持優先級翻轉。有如下三種協議屬性:
PTHREAD_PRIO_NONE:線程的優先級和調度不會受到互斥鎖擁有權的影響。
PTHREAD_PRIO_INHERIT:使用該屬性值能夠避免優先級倒置。
PTHREAD_PRIO_PROTECT:當線程擁有一個或多個使用初始化的互斥鎖屬性時,此協議值會影響其餘線程的優先級和調度。
4) 互斥量屬性優先級上限屬性
函數原型:
#include <pthread.h>
int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *restrict attr, int *restrict prioceiling);
int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling);
函數功能:
pthread_mutexattr_setprioceiling()可用來設置互斥鎖屬性對象的優先級上限屬性。prioceiling 指定已初始化互斥鎖的優先級上限。優先級上限定義執行互斥鎖保護的臨界段時的最低優先級。prioceiling 位於 SCHED_FIFO 所定義的優先級的最大範圍內。要避免優先級倒置,請將 prioceiling 設置爲高於或等於可能會鎖定特定互斥鎖的全部線程的最高優先級。oldceiling 包含之前的優先級上限值。
若是成功完成,pthread_mutexattr_setprioceiling() 會返回 0。其餘任何返回值都表示出現了錯誤。
若是出現如下任一狀況,pthread_mutexattr_setprioceiling() 將失敗並返回對應的值。
ENOSYS:選項_POSIX_THREAD_PRIO_PROTECT未定義並該實現不支持此函數。
EINVAL:attr 或 prioceiling 指定的值無效。
EPERM:調用方無權執行該操做。
pthread_mutexattr_getprioceiling()函數可用來獲取互斥鎖屬性對象的優先級上限屬性,返回 prioceiling 中已初始化互斥鎖的優先級上限。
5) 共享互斥量屬性
函數原型:
int pthread_mutexattr_getpshared(const pthread_mutexattr_t * restrict attr, int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
函數功能:
pthread_mutexattr_getpshared()可爲屬性對象 mattr 獲取 pshared 的當前值,該值爲PTHREAD_PROCESS_SHARED或 PTHREAD_PROCESS_PRIVATE。該函數成功完成以後會返回零。其餘任何返回值都表示出現了錯誤。若是出現如下狀況,該函數將失敗並返回對應的值。EINVAL:由 mattr指定的值無效。
要在多個進程中的線程之間共享互斥量,能夠利用pthread_mutexattr_setpshared()函數,在共享內存中建立互斥量,並將 pshared 屬性設置爲 PTHREAD_PROCESS_SHARED。
15.2互斥量
1) 初始化和刪除互斥量
函數原型:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
函數功能:
若是針對之前初始化的但還沒有銷燬的互斥鎖調用 pthread_mutex_init(),則該互斥鎖不會從新初始化。若是屬主沒法使狀態保持一致,請勿調用 pthread_mutex_init(),而是解除鎖定該互斥鎖。在這種狀況下,全部等待的線程都將被喚醒。之後對 pthread_mutex_lock() 的全部調用將沒法獲取互斥鎖,並將返回錯誤代碼 ENOTRECOVERABLE。如今,經過調用 pthread_mutex_destroy() 來取消初始化該互斥鎖,便可使其狀態保持一致。調用 pthread_mutex_init() 可從新初始化互斥鎖。
2) 互斥量鎖操做
函數原型:
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
函數功能:
鎖操做主要包括加鎖pthread_mutex_lock()、解鎖 pthread_mutex_unlock()和測試加鎖 pthread_mutex_trylock()三個,不論哪一種類型的鎖,都不可能被兩個不一樣的線程同時獲得,而必須等待解鎖。對於普通鎖和適應鎖類型, 解鎖者能夠是同進程內任何線程;而檢錯鎖則必須由加鎖者解鎖纔有效,不然返回EPERM;對於嵌套鎖,文檔和實現要求必須由加鎖者解鎖。在同一進程中的線程,若是加鎖後沒有解鎖,則任何其餘線程都沒法再得到鎖。 pthread_mutex_trylock()語義與pthread_mutex_lock()相似,不一樣的是在鎖已經被佔據時返回EBUSY而不是掛起等待。
3) 互斥量高級鎖操做
函數原型:
#include <pthread.h>
#include <time.h>
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);
函數功能:
當線程試圖獲取一個已加鎖的互斥變量時,pthread_mutex_timedlock互斥量原語容許綁定線程阻塞的時間。pthread_mutex_timedlock函數與pthread_mutex_lock是基本等價的,可是在達到超時時間值時,pthread_mutex_timedlock不會對互斥量進行加鎖,而是返回錯誤碼ETIMEDOUT。
4) 互斥鎖的優先級上限
函數原型:
#include <pthread.h>
int pthread_mutex_getprioceiling(const pthread_mutex_t *restrict mutex,int *restrict prioceiling);
int pthread_mutex_setprioceiling(pthread_mutex_t *restrict mutex,int prioceiling, int *restrict old_ceiling);
函數功能:
pthread_mutex_getprioceiling()會返回 mutex 的優先級上限 prioceiling。pthread_mutex_setprioceiling()可更改互斥鎖 mutex 的優先級上限 prioceiling。可鎖定互斥鎖(若是未鎖定的話),或者一直處於阻塞狀態,直到 pthread_mutex_setprioceiling()成功鎖定該互斥鎖,更改該互斥鎖的優先級上限並將該互斥鎖釋放爲止。鎖定互斥鎖的過程無需遵循優先級保護協議。
十六 線程管理
16.1線程屬性
1) 線程屬性的初始化與刪除
函數原型:
#include <pthread.h>
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_init(pthread_attr_t *attr);
函數功能:
線程具備屬性,用pthread_attr_t()表示,在對該結構進行處理以前必須進行初始化,在使用後須要對其去除初始化。咱們用pthread_attr_init()函數對其初始化,用pthread_attr_destroy()對其去除初始化。調用pthread_attr_init()以後,pthread_t結構所包含的內容就是操做系統實現支持的線程全部屬性的默認值。
線程屬性結構以下:
typedef struct
{
int detachstate; /*線程的分離狀態*/
int schedpolicy; /*線程調度策略*/
structsched_param schedparam; /*線程的調度參數*/
int inheritsched; /*線程的繼承性*/
int scope; /*線程的做用域*/
size_t guardsize; /*線程棧末尾的警惕緩衝區大小*/
int stackaddr_set;
void* stackaddr; /*線程棧的位置*/
size_t stacksize; /*線程棧的大小*/
}pthread_attr_t;
2) 線程屬性的分離狀態
函數原型:
#include <pthread.h>
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
函數功能:
線程的分離狀態決定一個線程以什麼樣的方式來終止本身。在默認狀況下線程是非分離狀態的,這種狀況下,原有的線程等待建立的線程結束。只有當pthread_join()返回時,建立的線程纔算終止,才能釋放本身佔用的系統資源。
而分離線程不是這樣子的,它沒有被其餘的線程所等待,本身運行結束了,線程也就終止了,立刻釋放系統資源。程序員應該根據本身的須要,選擇適當的分離狀態。因此若是咱們在建立線程時就知道不須要了解線程的終止狀態,則能夠pthread_attr_t結構中的detachstate線程屬性,讓線程以分離狀態啓動。
可使用pthread_attr_setdetachstate()把線程屬性detachstate設置爲下面的兩個合法值之一:設置爲PTHREAD_CREATE_DETACHED,以分離狀態啓動線程;或者設置爲PTHREAD_CREATE_JOINABLE,正常啓動線程。可使用pthread_attr_getdetachstate()獲取當前的datachstate線程屬性。
3) 線程屬性的繼承性
函數原型:
#include <pthread.h>
int pthread_attr_getinheritsched(const pthread_attr_t *restrict attr,int *restrict inheritsched);
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
函數功能:
這兩個函數分別用來設置和獲得線程的繼承性。
這兩個函數具備兩個參數,第1個是指向屬性對象的指針,第2個是繼承性或指向繼承性的指針。繼承性決定調度的參數是從建立的進程中繼承仍是使用在schedpolicy和schedparam屬性中顯式設置的調度信息。Pthreads不爲inheritsched指定默認值,所以若是你關心線程的調度策略和參數,必須先設置該屬性。
繼承性的可能值是PTHREAD_INHERIT_SCHED(表示新現成將繼承建立線程的調度策略和參數)和PTHREAD_EXPLICIT_SCHED(表示使用在schedpolicy和schedparam屬性中顯式設置的調度策略和參數)。
若是你須要顯式的設置一個線程的調度策略或參數,那麼你必須在設置以前將inheritsched屬性設置爲PTHREAD_EXPLICIT_SCHED.線程屬性結構以下:
4) 線程屬性的調度策略
函數原型:
#include <pthread.h>
int pthread_attr_getschedpolicy(const pthread_attr_t *restrict attr,int *restrict policy);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
函數功能:
這兩個函數分別用來設置和獲得線程的調度策略。
這兩個函數具備兩個參數,第1個參數是指向屬性對象的指針,第2個參數是調度策略或指向調度策略的指針。調度策略可能的值是先進先出(SCHED_FIFO)、輪轉法(SCHED_RR),或其它(SCHED_OTHER)。
SCHED_FIFO策略容許一個線程運行直到有更高優先級的線程準備好,或者直到它自願阻塞本身。在SCHED_FIFO調度策略下,當有一個線程準備好時,除非有平等或更高優先級的線程已經在運行,不然它會很快開始執行。
SCHED_RR(輪循)策略是基本相同的,不一樣之處在於:若是有一個SCHED_RR
策略的線程執行了超過一個固定的時期(時間片間隔)沒有阻塞,而另外的SCHED_RR或SCHBD_FIPO策略的相同優先級的線程準備好時,運行的線程將被搶佔以便準備好的線程能夠執行。
當有SCHED_FIFO或SCHED_RR策賂的線程在一個條件變量上等持或等持加鎖同一個互斥量時,它們將以優先級順序被喚醒。即,若是一個低優先級的SCHED_FIFO線程和一個高優先織的SCHED_FIFO線程都在等待鎖相同的互斥且,則當互斥量被解鎖時,高優先級線程將老是被首先解除阻塞。
5) 線程屬性的調度參數
函數原型:
#include <pthread.h>
int pthread_attr_getschedparam(const pthread_attr_t *restrict attr,struct sched_param *restrict param);
int pthread_attr_setschedparam(pthread_attr_t *restrict attr,const struct sched_param *restrict param);
函數功能:
這兩個函數分別用來設置和獲得線程的調度參數。
這兩個函數具備兩個參數,第1個參數是指向屬性對象的指針,第2個參數是sched_param結構或指向該結構的指針。
結構sched_param的子成員sched_priority控制一個優先權值,大的優先權值對應高的優先權。系統支持的最大和最小優先權值能夠用sched_get_priority_max函數和sched_get_priority_min函數分別獲得。
注意:若是不是編寫實時程序,不建議修改線程的優先級。由於,調度策略是一件很是複雜的事情,若是不正確使用會致使程序錯誤,從而致使死鎖等問題。如:在多線程應用程序中爲線程設置不一樣的優先級別,有可能由於共享資源而致使優先級倒置。
6) 線程屬性的堆棧大小
函數原型:
#include <pthread.h>
int pthread_attr_getstacksize(const pthread_attr_t *restrict attr,size_t *restrict stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
函數功能:
這兩個函數用於獲取和設置堆棧大小屬性。stacksize屬性定義系統分配的棧大小(以字節爲單位),size不該小於系統定義的最小棧大小。
7) 線程屬性的堆棧地址
函數原型:
#include <pthread.h>
int pthread_attr_getscope(const pthread_attr_t * attr, int * scope );
int pthread_attr_setscope(pthread_attr_t*, int scope);
函數功能:
這兩個函數分別用來設置和獲得線程的做用域。attr是線程屬性變量,scope是線程的做用域。若成功返回0,若失敗返回-1。做用域控制線程是否在進程內或在系統級上競爭資源,可能的值是:PTHREAD_SCOPE_PROCESS(進程內競爭資源)、PTHREAD_SCOPE_SYSTEM(系統級競爭資源)。
16.2線程
1) 線程的建立
函數原型:
#include <pthread.h>
int pthread_create(pthread_t *restrict thread,const pthread_attr_t *restrict attr,void *(*start_routine)(void*), void *restrict arg);
函數功能:
pthread_create是建立線程函數。若成功則返回0,不然返回出錯編號。thread爲指向線程標識符的指針。attr用來設置線程屬性。第三個參數是線程運行函數的起始地址。arg是運行函數的參數。
2) 線程的終結
函數原型:
#include <pthread.h>
void pthread_exit(void *value_ptr);
函數功能:
使用函數pthread_exit()退出線程,這是線程的主動行爲。
3) 線程的分離
函數原型:
#include <pthread.h>
int pthread_detach(pthread_t thread);
函數功能:
該函數將子線程的狀態設置爲分離的,則該線程運行結束後會自動釋放全部資源。
4) 等待線程結束
函數原型:
#include <pthread.h>
int pthread_join(pthread_t thread, void **value_ptr);
函數功能:
pthread_join()使一個線程等待另外一個線程結束。代碼中若是沒有pthread_join主線程會很快結束從而使整個進程結束,從而使建立的線程沒有機會開始執行就結束了。加入pthread_join後,主線程會一直等待直到等待的線程結束本身才結束,使建立的線程有機會執行。
5) 得到線程自身ID
函數原型:
#include <pthread.h>
pthread_t pthread_self(void);
函數功能:
該函數得到線程自身的ID。pthread_t的類型爲unsigned long int,因此在打印的時候要使用%lu方式,不然將產生奇怪的結果。
6) 比較線程ID
函數原型:
#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
函數功能:
比較兩個線程的ID是否同樣,若是同樣,返回非0,不然返回0。
7) 動態包比較
函數原型:
#include <pthread.h>
int pthread_once(pthread_once_t *once_control,void (*init_routine)(void));
pthread_once_t once_control = PTHREAD_ONCE_INIT;
函數功能:
該函數使用初值爲PTHREAD_ONCE_INIT的once_control變量保證init_routine()函數在本進程執行序列中僅執行一次。
8) 獲取/設置動態線程調度參數
函數原型:
#include <pthread.h>
int pthread_getschedparam(pthread_t thread, int *restrict policy,struct sched_param *restrict param);
int pthread_setschedparam(pthread_t thread, int policy,const struct sched_param *param);
函數功能:
前面的那些函數pthread_attr_setschedparam()與pthread_attr_getschedparam()只能經過線程的屬性對象pthread_attr_t來設置線程的調度策略和優先級,不可以直接設置正在運行的線程的調度策略和優先級,而這兩個函數能夠直接設置。
注意,當pthread_setschedparam()函數的參數 policy == SCHED_RR 或者 SCHED_FIFO 時,程序必需要在超級用戶下運行。
16.3進程原語與線程原語的比較
進程原語 |
線程原語 |
描述 |
fork |
pthread_create |
建立新的控制流 |
exit |
pthread_exit |
從現有的控制流中退出 |
waitpid |
pthread_join |
從控制流中獲得退出狀態 |
atexit |
pthread_cleanup_push |
註冊在退出控制流時調用的函數 |
getpid |
pthread_self |
獲取控制流的ID |
abort |
pthread_cancel |
請求控制流的非正常退出 |
在默認狀況下,線程的終止狀態會保存到對該線程調用pthread_join(),若是線程已經處於分離狀態,線程的底層存儲資源能夠再線程終止時當即被收回。當線程被分離時,並不能用pthread_join()函數等待它的終止狀態。對分離狀態的線程進行pthread_join()的調用能夠產生失敗,返回EINVAL。pthread_detach()調用能夠用因而線程進入分離狀態。[apue]
十七 條件變量
17.1條件變量
條件變量時線程可用的另外一種同步機制。條件變量給多個線程提供了一個會合的場所。條件變量與互斥量一塊兒使用時,容許線程以無競爭的方式等待特定的條件發生。
17.2條件變量屬性
1) 屬性初始化與刪除
函數原型:
#include <pthread.h>
int pthread_condattr_destroy(pthread_condattr_t *attr);
int pthread_condattr_init(pthread_condattr_t *attr);
函數功能:
這兩個函數用於建立和銷燬條件變量屬性對象。若成功返回0,若失敗返回錯誤編號。一旦某個條件變量對象被初始化了,咱們就能夠利用下面函數來查看或修改特定屬性了。
2) 進程共享條件變量屬性
函數原型:
#include <pthread.h>
int pthread_condattr_getpshared(const pthread_condattr_t *restrict attr,int *restrict pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr,int pshared);
函數功能:
這兩個函數用來得到或者設置進程共享條件變量屬性。
17.3條件變量
1) 初始化與刪除
函數原型:
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
函數功能:
條件變量使用以前必須首先進行初始化,pthread_cond_t數據類型表明的條件變量能夠用兩種方式進行初始化,能夠把常量PTHREAD_COND_INITIALIZER賦給靜態變量分配的條件變量,可是若是條件變量時動態分配的,可使用pthread_cond_init函數進行初始化。在釋放底層的內存空間以前,可使用pthread_cond_destroy()函數對條件變量進行去除初始化。
2) 信號量與廣播
函數原型:
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
函數功能:
pthread_cond_signal()做用是發送一個信號給另一個正在處於阻塞等待狀態的線程,使其脫離阻塞狀態,繼續執行.若是沒有線程處在阻塞等待狀態,pthread_cond_signal也會成功返回。應該在互斥量被鎖定後調用。若不止一個線程阻塞在條件變量上,則應用pthread_cond_broadcast()向其它因此線程發生信號
3) 等待(阻塞)
函數原型:
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
函數功能:
使用pthread_cond_wait()等待條件變爲真,若是再給定的時間內條件不能知足,那麼會生成一個表明出錯碼的返回變量。傳遞給pthread_cond_wait()的互斥量對條件進行保護,調用者把鎖住的互斥量傳給函數,函數把調用線程放到等待條件的線程列表上,而後對互斥量解鎖,這兩個操做室原子操做。這樣就關閉了條件檢查的線程和線程進入休眠狀態等待條件改變着兩個操做之間的時間通道,這樣線程就不會錯過條件的任何變化。pthread_cond_wait()返回時,互斥量再次被鎖住。
pthread_cond_timedwait()函數的工做方式與pthread_cond_wait()類似,只是多了一個timeout。timeout值指定了等待等待的時間。
十八 附錄
18.1UNIX系統所須要的頭文件
Posix標準C頭文件(24項)
<assert.h> ---------------------- 驗證程序斷言
<complex.h> ---------------------- 支持複數算術運算
<ctype.h> ---------------------- 字符類型
<errno.h> ---------------------- 出錯碼
<fenv.h> ---------------------- 浮點環境
<float.h> ---------------------- 浮點常量
<inttypes.h> ---------------------- 整型格式轉換
<iso646.h> ---------------------- 替代關係操做符宏
<limits.h> ---------------------- 實現常量
<locale.h> ---------------------- 局部類別
<math.h> ---------------------- 數學常量
<setjmp.h> ---------------------- 非局部goto
<signal.h> ---------------------- 信號
<stdarg.h> ---------------------- 可變參數表
<stdbool.h> ---------------------- 布爾類型和值
<stddef.h> ---------------------- 標準定義
<stdint.h> ---------------------- 整型
<stdio.h> ---------------------- 標準I/O庫
<stdlib.h> ---------------------- 實用程序庫函數
<string.h> ---------------------- 字符串操做
<tgmath.h> ---------------------- 通用類型數學宏
<time.h> ---------------------- 時間和日期
<wchar.h> ---------------------- 擴展的多字節和寬字符支持
<wctype.h> ---------------------- 寬字符分類和映射支持
POSIX標準定義的基本頭文件(26項)
<dirent.h> ---------------------- 目錄項
<fcntl.h> ---------------------- 文件控制
<fnmatch.h> ---------------------- 文件名匹配類型
<glob.h> ---------------------- 路徑名模式匹配類型
<grp.h> ---------------------- 組文件
<netdb.h> ---------------------- 網絡數據庫操做
<pwd.h> ---------------------- 口令文件
<regex.h> ---------------------- 正則表達式
<tar.h> ---------------------- tar歸檔值
<termios.h> ---------------------- 終端I/O
<unistd.h> ---------------------- 符號常量
<utime.h> ---------------------- 文件時間
<wordexp.h> ---------------------- 字擴展類型
<arpa/inet.h> ---------------------- Internet定義
<net/if.h> ---------------------- 套接字本地接口
<netinet/in.h> ---------------------- Internet地址族
<netinet/tcp.h> ---------------------- 傳輸控制協議定義
<sys/mman.h> ---------------------- 內存管理聲明
<sys/select.h> ---------------------- select函數
<sys/socket.h> ---------------------- 套接字接口
<sys/stat.h> ---------------------- 文件狀態
<sys/times.h> ---------------------- 進程時間
<sys/types.h> ---------------------- 基本系統數據類型
<sys/un.h> ---------------------- UNIX域套接字定義
<sys/utsname.h> ---------------------- 系統名
<sys/wait.h> ---------------------- 進程控制
POSIX標準定義的XSI擴展頭文件(26項)
<cpio.h> ---------------------- cpio歸檔值
<dlfcn.h> ---------------------- 動態連接
<fmtmsg.h> ---------------------- 消息顯示結構
<ftw.h> ---------------------- 文件樹漫遊
<iconv.h> ---------------------- 代碼集轉換實用程序
<langinfo.h> ---------------------- 語言信息常量
<libgen.h> ---------------------- 模式匹配函數定義
<monetary.h> ---------------------- 貨幣類型
<ndbm.h> ---------------------- 數據庫操做
<nl_types.h> ---------------------- 消息類別
<poll.h> ---------------------- 輪詢函數
<search.h> ---------------------- 搜索表
<strings.h> ---------------------- 字符串操做
<syslog.h> ---------------------- 系統出錯日誌記錄
<ucontext.h> ---------------------- 用戶上下文
<ulimit.h> ---------------------- 用戶限制
<utmpx.h> ---------------------- 用戶賬戶數據庫
<sys/ipc.h> ---------------------- IPC
<sys/msg.h> ---------------------- 消息隊列
<sys/resource.h> ------------------- 資源操做
<sys/sem.h> ---------------------- 信號量
<sys/shm.h> ---------------------- 共享存儲
<sys/statvfs.h> ---------------------- 文件系統信息
<sys/time.h> ---------------------- 時間類型
<sys/timeb.h> ---------------------- 附加的日期和時間定義
<sys/uio.h> ---------------------- 矢量I/O操做
POSIX標準定義的可選頭文件(8項)
<aio.h> ---------------------- 異步I/O
<mqueue.h> ---------------------- 消息隊列
<pthread.h> ---------------------- 線程
<sched.h> ---------------------- 執行調度
<semaphore.h> ---------------------- 信號量
<spawn.h> ---------------------- 實時spawn接口
<stropts.h> ---------------------- XSI STREAMS接口
<trace.h> ---------------------- 時間跟蹤
---------------------------------------------------------------------------------------------------
參考文獻
[1] W.Richard Stevens, Stephen A.Rago. UNIX環境高級編程(第2版).
[2] David R.Butenhof. POSIX多線程程序設計
[3] the User’s Guide for the POSIX API support provided in RTEMS
[4] Standard for Information Technology–Portable Operating System Interface(POSIX®)
[5] http://www.cnblogs.com/mywolrd/archive/2009/02/05/1930707.html#phtread_ref
[6] http://www.cnblogs.com/jishume/articles/2216054.html
[7] http://www.ibm.com/developerworks/cn/linux/thread/posix_thread1/index.html#icomments