一、相關API
1、程序的建立fork()
#include <unistd.h>
pid_t fork(void);
pid_t vfork(void);
傳回值: > 0 父程序 parent process
==0 子程序 child process
< 0(-1) 失敗
fork的特點:
第一個特點: 一次調用,兩次傳回,傳回大于0(值就是子程序的id号)表示父程序,等于0表示子程序
子程序會複制父程序的所有資源(代碼段,資料段)
第二個特點:父程序總共分成三個部分
第一個部分在fork之前
第二個部分fork成功之後,在id>0情況下的那部分代碼
第三個部分fork後面的
總結:
第一點:fork()的套路
if(>0){ 父程序代碼 }else if(==0){ 程式員建立子程序需要并發執行的任務代碼 }else{ 錯誤 }
第二點:vfork建立的子程序共享父程序的資源,vfork建立的子程序一定優先于父程序運作
2、程序的退出跟回收exit()/wait()
#include <stdlib.h>
void exit(int status); //退出程序的同時重新整理緩沖區
void _exit(int status);//退出程序的時候不重新整理緩沖區
參數:status -->程序退出時候的值
對比return: 差別一:return是C語言中關鍵字,exit()是函數
差別二:return是傳回函數調用的結果,exit()是結束整個程序
#include <sys/wait.h>
pid_t wait(int *stat_loc);--->收子程序結束傳回值(收屍)
傳回值:成功 傳回值回收到的那個子程序的ID,失敗 -1
參數:stat_loc -->用來存放程序退出時候的狀态資訊
不是存放退出值,退出值僅僅隻是狀态資訊中的一部分
特點:會讓父程序一直阻塞,直到成功回收到子程序為止
pid_t waitpid(pid_t pid, int *stat_loc, int options);
傳回值:成功 傳回值回收到的那個子程序的ID,失敗 -1
參數: pid --> 小于-1 waitpid(-1200,&status,options);回收程序組id是1200的其中一個
等于-1 waitpid(-1,&status,options);回收任意一個子程序(不要求同組)
等于0 waitpid(0,&status,options); 回收本程序組中任意一個子程序
大于0 waitpid(1200,&status,options); 指定回收id是1200的子程序
stat_loc -->跟wait一樣
options -->WN0HANG 非阻塞等待,等得到就等,等不到就直接退出
0 阻塞等待
3、擷取目前程序的id以及父程序的id
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); //擷取子程序ID
pid_t getppid(void); //擷取父程序ID
gid_t getgid(void); //擷取程序組ID
4、使用函數執行shell指令
#include <stdlib.h>
#include <unistd.h>
int system(const char *command);
傳回值:失敗 -1
參數: command -->你要執行的shell指令或者你要執行程式完整的指令名
int execl(const char *path, const char *arg, ...);
參數: path -->你要執行的程式/指令所在的路徑
arg -->你要執行的指令/程式
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
參數: file-->即将被加載執行的檔案名
argv-->儲存即将被執行的參數的數組
envp-->使用者自定義的環境變量數組
總結: l -->參數以清單的形式逐一列舉
e -->參數中可以設定環境變量
v -->參數用一個指針數組存放
p -->傳遞程式/指令的名字
二、程序間通信
(一)無名管道和有名管道
1、建立無名管道
#include <unistd.h>
int pipe(int fildes[2]);
傳回值:成功 0 失敗 -1
參數: fildes[2] -->存放的是兩個檔案描述符
fildes[0]讀端的檔案描述符
fildes[1]寫端的檔案描述符
特點:
有固定的讀端(fd[0])跟寫端(fd[1])
當管道中沒有資料可以讀的時候,調用read會阻塞
隻能用于具有血緣關系的程序之間(父子程序,兄弟程序之間)
2、建立有名管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
傳回值:成功 0 失敗 -1
參數: pathname -->你要建立的有名管道的名字(帶路徑)
mode -->0777
特點:
有名字,生成一個管道檔案,用于通信
當管道中沒有資料可以讀的時候,調用read會阻塞
任意兩個不同程序之間都能通信
3、判斷檔案是否存在
#include <unistd.h>
int access(const char *path, int amode);
功能:判斷一個檔案是否存在,參數用來判斷檔案是否可讀、是否可寫、是否可執行
傳回值:符合你要求的判斷條件傳回0 否則 -1
參數: path -->檔案的路徑
amode -->R_OK, W_OK, X_OK ,F_OK
(二)信号:
作用是當一個程序發送信号給另外一個程序的時候,可以通過該信号去控制另外一個程序執行程式員想幹的事情
1、發送信号
#include <signal.h>
int kill(pid_t pid, int sig);
參數: pid -->你要發送信号的那個程序的id
sig -->你要發送的信号
int sigqueue(pid_t pid, int sig, const union sigval value);
參數:union sigval {
int sival_int;
void *sival_ptr; //void *萬能指針
};//存放你想發送的額外資料
跟kill的差別:sigqueue買一送一(發送信号的同時可以額外發送其他資料給到程序)
2、捕捉信号并改變信号的響應動作
#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);
傳回值:最近一次調用時第二個參數的值(函數指針)
參數:sig -->你想要捕捉的信号
第二個參數有三種情況:
情況一:
void (*func)(int) -->函數指針,你想要改變的信号動作就靠該函數實作
情況二:
SIG_DFL -->按照信号預設的動作響應
情況三:
SIG_IGN -->忽略信号,收到信号之後不做任何響應,直接舍棄
注意:在所有的信号中有兩個信号是既不能改變預設動作也不能忽略,SIGKILL和SIGSTOP
int sigaction(int sig, const struct sigaction *restrict act,struct sigaction *restrict oact);
參數: struct sigaction
{
void(*)(int) sa_handler //跟signal中函數指針一模一樣
sigset_t sa_mask //信号阻塞掩碼??
int sa_flags //設定0選擇sa_handler
//設定SA_SIGINFO表示選擇sa_sigaction
void(*)(int,siginfo_t *,void *) sa_sigaction//另外一個信号響應函數,接收額外資料
}
void(*)(int,siginfo_t *,void *)
siginfo_t
{
si_int -->存放union sigval裡面的sival_int
si_ptr -->存放union sigval裡面的sival_ptr
si_pid -->存放發送信号的那個程序的id
}
oact-->原有信号的處理參數,一般為NULL
3、其它簡單函數
#include <signal.h>
int pause(void);//阻塞目前程序等待信号到來
int raise(int sig);//自己給自己發送信号
unsigned alarm(unsigned seconds);//定時器,alarm(5);過5秒之後自己給自己發送SIGALRM
4、信号的阻塞或屏蔽
#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set,sigset_t *restrict oset);//設定信号阻塞的函數
傳回值:成功 0 失敗 -1
參數:how -->SIG_BLOCK //設定阻塞 将set對應信号添加到原本的信号集合中
SIG_SETMASK //設定阻塞 用set替換原本的信号集合中的信号
SIG_UNBLOCK //解除阻塞
sigset_t --> 系統定義的一種變量類型,專門用來存放你想要阻塞的信号
稱之為信号阻塞掩碼集
操作信号阻塞掩碼集合的函數
int sigemptyset(sigset_t *set); //清空掩碼集
int sigfillset(sigset_t *set); //将所有的linux信号添加到集合中
int sigaddset(sigset_t *set, int signum);//将具體的某個信号添加到集合
int sigdelset(sigset_t *set, int signum);//将具體的某個信号從集合删除
int sigismember(const sigset_t *set, int signum);//判斷某個信号在不在集合 傳回1是成員 傳回0不是成員
注意:信号設定阻塞僅僅隻是将信号暫時挂起,信号依然存在(等到解除阻塞又能重新響應)
**********************************************************************************************************************************************
《system-V IPC通信 》:指的就是共享記憶體,消息隊列,信号量
linux指令: ipcs -s 檢視目前系統所有的信号量
ipcs -m 檢視目前系統所有的共享記憶體
ipcs -q 檢視目前系統所有的消息隊列
ipcs -a 檢視目前系統所有的IPC對象
ipcrm -s 信号量id 删除信号量
ipcrm -m 共享記憶體id 删除共享記憶體
ipcrm -q 消息隊列id 删除消息隊列
(三)信号量:用來協調多個程序對應共享資源的通路
特點:當信号量的值為0,你還想p操作,會阻塞目前程序
信号量的值是不可能為負數的
v操作永遠不會阻塞
1、建立信号量
#include <sys/sem.h>
#include <sys/ipc.h>
int semget(key_t key, int nsems, int semflg);
傳回值:成功 信号量的id 失敗 -1
參數:key -->鍵值,確定唯一性
産生鍵值兩種方法
第一種:自己随便寫一個(正整數)
第二種:使用系統提供的ftok()生成一個鍵值
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
傳回值:成功 傳回鍵值 失敗 -1
參數:pathname -->合法的linux路徑
proj_id -->随便寫個整數
ftok(".",200); ftok(".",199);
nsems -->你打算建立多少個信号量
semflg -->IPC_CREAT信号量不存在則建立
IPC_EXCL信号量已存在則報錯
0777 信号量的通路權限
2、擷取或設定信号量的相關屬性
#include <sys/sem.h>
#include <sys/ipc.h>
int semctl(int semid, int semnum, int cmd, ...);
參數: semid -->信号量的ID,semget的傳回值
semnum -->信号量的序号,從0開始
cmd -->GETVAL //擷取信号量值
int value=semctl(id,0,GETVAL);傳回值給value
SETVAL //設定信号量值
semctl(id,0,SETVAL,10);//将第一個信号量值設定為10
IPC_RMID //删除信号量
3、信号量的PV操作
#include <sys/sem.h>
#include <sys/ipc.h>
int semop(int semid, struct sembuf *sops, size_t nsops);
傳回值:
參數:struct sembuf
{
short sem_num 信号量的序号
short sem_op 決定你究竟是想P操作還是V操作,負數P操作,正數V操作
short sem_flg SEM_UNDO(操作完信号量之後,恢複成原本值)
}
nsops -->信号量struct sembuf個數
(四)共享記憶體:效率最高的IPC
1、申請共享記憶體
#include <sys/shm.h>
#include <sys/ipc.h>
int shmget(key_t key, size_t size, int shmflg);
傳回值:成功 共享記憶體的ID 失敗 -1
參數:size -->你打算申請多少的記憶體,位元組,一般設定成512的整數倍
shmflg->IPC_CREAT共享記憶體不存在則建立
IPC_EXCL共享記憶體已存在則報錯
0777 共享記憶體的通路權限
2、對共享記憶體進行映射或解除映射
#include <sys/shm.h>
#include <sys/ipc.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
參數:shmid-->共享記憶體id
shmaddr -->一般為NULL
shmflg -->一般為0
傳回值:成功傳回共享記憶體的首位址
失敗 -1
3、擷取、設定共享記憶體相關屬性或删除共享記憶體
#include <sys/shm.h>
#include <sys/ipc.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
參數:cmd -->IPC_STAT //擷取共享記憶體的屬性資訊
IPC_SET //設定共享記憶體的屬性資訊
IPC_RMID //删除共享記憶體
struct shmid_ds -->用來存放共享記憶體的屬性資訊
(五)消息隊列
1、建立消息隊列
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
參數:shmflg->IPC_CREAT消息隊列不存在則建立
IPC_EXCL消息隊列已存在則報錯
0777 消息隊列的通路權限
2、收發資訊
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
傳回值:成功 0 失敗 -1
參數:msgflg -->預設設定0 //阻塞
IPC_NOWAIT //非阻塞
msgp--->要發送資料的存儲區域指針
msgsz-->要發送資料的大小
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
參數:msgtyp -->你要接收的資訊類型
msgp--->要接收資料的存儲區域指針
msgsz-->要接收資料的大小
重點:發送消息的格式是有要求的,要求使用者自定資料類型
struct msgbuf
{
long msgtype; //表明消息類型
char truemsg[50];//真實的資訊内容
};
struct singlelist
{
int num;//真實的資料
char buf[10]; //next指針
};
3、删除消息隊列
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
參數:cmd-->IPC_STAT 擷取MSG的資訊
IPC_SET 設定MSG的資訊
IPC_RMID 删除MSG
buf-->存放資訊結構體緩沖區