Linux进程相关API及多进程间通信

一、相关API

1、进程的创建fork()
                    #include
                    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
                    void exit(int status); //退出进程的同时刷新缓冲区
                    void _exit(int status);//退出进程的时候不刷新缓冲区
                        参数:status -->进程退出时候的值
                        对比return:    区别一:return是C语言中关键字,exit()是函数
                                    区别二:return是返回函数调用的结果,exit()是结束整个进程
                    #include
                    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
                    #include
                    pid_t getpid(void);  //获取子进程ID
                    pid_t getppid(void); //获取父进程ID
                    gid_t getgid(void); //获取进程组ID
4、使用函数执行shell命令
                    #include
                    #include
                    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
                    int pipe(int fildes[2]);
                        返回值:成功 0 失败 -1
                        参数:    fildes[2] -->存放的是两个文件描述符
                                fildes[0]读端的文件描述符
                                fildes[1]写端的文件描述符
                        特点:
                            有固定的读端(fd[0])跟写端(fd[1])
                            当管道中没有数据可以读的时候,调用read会阻塞
                            只能用于具有血缘关系的进程之间(父子进程,兄弟进程之间)
                2、创建有名管道
                    #include
                    #include
                    int mkfifo(const char *pathname, mode_t mode);
                        返回值:成功 0 失败 -1
                        参数:    pathname -->你要创建的有名管道的名字(带路径)
                                mode -->0777 
                        特点:
                            有名字,生成一个管道文件,用于通信
                            当管道中没有数据可以读的时候,调用read会阻塞
                            任意两个不同进程之间都能通信
                3、判断文件是否存在
                    #include
                    int access(const char *path, int amode);
                        功能:判断一个文件是否存在,参数用来判断文件是否可读、是否可写、是否可执行
                        返回值:符合你要求的判断条件返回0  否则 -1
                        参数:    path -->文件的路径
                                amode -->R_OK, W_OK,  X_OK ,F_OK
  (二)信号:

               作用是当一个进程发送信号给另外一个进程的时候,可以通过该信号去控制另外一个进程执行程序员想干的事情
                1、发送信号
                    #include
                    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
                    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
                    int pause(void);//阻塞当前进程等待信号到来
                    int raise(int sig);//自己给自己发送信号
                    unsigned alarm(unsigned seconds);//定时器,alarm(5);过5秒之后自己给自己发送SIGALRM 
                4、信号的阻塞或屏蔽
                    #include
                    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
                    #include
                    int semget(key_t key, int nsems, int semflg);
                        返回值:成功 信号量的id  失败 -1
                        参数:key -->键值,确保唯一性
                            产生键值两种方法
                            第一种:自己随便写一个(正整数)
                            第二种:使用系统提供的ftok()生成一个键值
                                #include
                                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
                    #include
                    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
                    #include
                    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
                    #include
                    int shmget(key_t key, size_t size, int shmflg);
                        返回值:成功 共享内存的ID  失败 -1
                        参数:size -->你打算申请多少的内存,字节,一般设置成512的整数倍
                             shmflg->IPC_CREAT共享内存不存在则创建
                                     IPC_EXCL共享内存已存在则报错
                                     0777    共享内存的访问权限
                2、对共享内存进行映射或解除映射
                    #include
                    #include
                    void *shmat(int shmid, const void *shmaddr, int shmflg);
                    int shmdt(const void *shmaddr);
                        参数:shmid-->共享内存id
                             shmaddr -->一般为NULL
                             shmflg -->一般为0
                        返回值:成功返回共享内存的首地址
                                失败 -1
                3、获取、设置共享内存相关属性或删除共享内存
                    #include
                    #include
                    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
                        参数:cmd -->IPC_STAT //获取共享内存的属性信息
                                  IPC_SET //设置共享内存的属性信息
                                  IPC_RMID //删除共享内存
                             struct shmid_ds -->用来存放共享内存的属性信息
      (五)消息队列
                1、创建消息队列
                    #include
                    #include
                    int msgget(key_t key, int msgflg);
                        参数:shmflg->IPC_CREAT消息队列不存在则创建
                                      IPC_EXCL消息队列已存在则报错
                                      0777    消息队列的访问权限
                2、收发信息
                    #include
                    #include
                    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
                    #include
                    int msgctl(int msqid, int cmd, struct msqid_ds *buf);
                        参数:cmd-->IPC_STAT 获取MSG的信息
                                    IPC_SET  设置MSG的信息
                                    IPC_RMID 删除MSG
                              buf-->存放信息结构体缓冲区

你可能感兴趣的:(Linux)