天天看點

Linux程序相關API及多程序間通信

一、相關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-->存放資訊結構體緩沖區

繼續閱讀