Linux编程基础8.1~8.4 学习记录

2.命名管道

        mkfifo()函数创建命名管道(FIFO文件),命名管道与系统中的一个路径名关联,以文件的形式存在于文件系统中,通过FIFO的路径名访问FIFO文件,实现进程间通信。该函数存在于sys/type.h和sys/stat.h中,其声明如下:

int mkfifo(const char *pathname, mode_t mode);

        参数:pathname是管道文件的路径名,通过FIFO路径名访问FIFO文件;mode用于指定FIFO的权限。

        返回值:成功返回0;不成功返回-1并设置errno。

FIFO文件和普通文件的区别:

1.FIFO文件是对内存进行操作;普通文件是存储在硬盘。

2.对内存的的读取会比硬盘的读写要快很多;两个进程通过普通文件通信当然也是可以的。

一.消息队列:

        消息队列的本质是一个存放消息的链表,该链表由内核来维护。一个消息队列由一个标识符(即队列key)来标识。消息队列的通信机制传递的数据具有某种结构,而不是简单的字节流;向消息队列中写数据,实际上是向这个数据结构中插入一个新结点;从消息队列中读数据,实际上是从这个数据结构中删除一个结点;消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法;消息队列具有和管道一样的不足,每个数据块的最大长度是有上限的,系统上全体队列的最大总长度也是有上限的。

        1.消息缓冲区的结构定义如下:

struct msgbuf{
    long int
msgtype;       //消息类型
    anytype data;            //要发送的数据,可以为任意类型
};

        2.msgget()函数:

创建一个消息队列或获取一个已经存在的消息队列,函数存在于sys/msg.h中,其声明如下:

int msgget(key_t key, int msgflg);

        参数:key为消息队列的键值,通常为一个整数,若键值为IPC_PRIVATE,将会创建一个只能被创建消息队列的进程读写的消息队列。msgflg用于设置消息队列的创建方式或权限,通常是一个9位的权限与如下值进行位操作后获得:msgflg = mask | IPC_CREAT,若内核中不存在指定消息队列,则它会被创建;若已存在,则获取该消息队列;msgflg = mask | IPC_CREAT | IPC_EXCL时,若消息队列不存在,则它会被创建;若已存在,则msgget函数调用失败,返回-1,并设置errno为EEXIST。

        返回值:成功返回消息队列的标识符;不成功返回-1并设置errno。

        3.msgsnd()函数:

        该函数会向指定消息队列发送一个消息;如果msgflg = 0,调用函数的进程会被挂起,直到消息写入消息队列为止。存在于sys/msg.h中,其声明如下:

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

        参数:msqid为消息队列标识符,即msgget函数调用成功后的返回值;msgp为指向消息缓冲区的指针;msgsz表示消息中数据的长度,这个长度不包括长整型成员变量的长度;msgflg是标志位,可以设置为0或IPC_NOWAIT。

        返回值:成功返回消息队列的标识符;不成功,即消息队列已满或系统中消息数量达到上限时返回-1并设置errno。

        4.msgrcv()函数:

        从消息队列中读取消息,被读取的消息会从消息列表中移除。函数存在于sys/msg.h中,其声明如下:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

        参数:msqid为消息队列标识符,即msgget函数调用成功后的返回值;msgp指向所读取消息的结构体指针;msgsz表示消息中数据的长度,这个长度不包括长整型成员变量的长度;msgtyp从消息队列中读取的消息类型:( msgtyp = 0:获取队列中的第一个可用消息;msgtyp > 0:获取队列中与该值类型相同的第一个消息;msgtyp < 0:获取队列中消息类型小于或等于其绝对值的第一个消息。)msgflg为标志位(msgflg = 0:进程将阻塞等待消息的读取;msgflg = IPC_NOWAIT:进程未读取到指定消息时将立刻返回-1。)

        返回值:成功返回消息队列的标识符;不成功返回-1并设置errno。

        5.msgctl()函数:

        对指定消息队列进行控制。存在于sys/msg.h中,其声明如下:

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
struct msqid_ds {
    struct ipc_perm msg_perm;    //所有者和权限标识
    time_t msg_stime;            //最后一次发送消息的时间
    time_t msg_rtime;            //最后一次接收消息的时间
    time_t msg_ctime;            //最后改变的时间
    unsigned long __msg_cbytes;    //队列中当前数据字节数
    msgqnum_t msg_qnum;            //队列中当前消息数
    msglen_t msg_qbytes;        //队列中允许的最大字节数
    pid_t msg_lspid;            //最后发送消息的进程pid
    pid_t msg_lrpid;            //最后接收消息的进程pid
};

        参数:msqid为消息队列标识符,即msgget函数调用成功后的返回值;cmd为消息队列的处理命令(cmd = IPC_RMID:从系统内核中删除指定命令,使用命令ipcrm -q id可实现同样的功能;cmd = IPC_SET:若进程有权限,将内核管理的消息队列的当前属性值设置为参数buf各成员的值;cmd = IPC_STAT:将内核所管理的消息队列的当前属性值复制给参数buf。)buf是一个缓冲区,用于传递属性值给指定消息队列或从指定消息队列中获取属性值,其功能视cmd而定。

        返回值:成功返回消息队列的标识符;不成功返回-1并设置errno。

        6.键值和标识符

         键值(ID):ID是msgget函数的返回值,一个非负整数,属于进程间通信的内部名,用来确保使用同一个消息队列。内部名即在进程内部使用,是消息队列在进程级别的唯一标识,这样的标识方法是不能支持进程间通信的。

        标识符(key): key是实现进程与消息队列关联的关键,属于进程间通信的外部名,是消息队列在内存级别的唯一标识。当多个进程,针对同一个key调用msgget函数,这些进程得到的ID其实是标识了同一个进程间通信的结构。多个进程间就可以通过这个进程间通信的结构进行通信。

二.信号量:

        信号量是专门用来解决进程同步与互斥问题的一种通信机制,它与信号无关;不同于管道、FIFO以及消息队列,一般不用来传输数据;信号量包括:表示资源数量的非负整型变量、修改信号量的原子操作P和V、该信号量下等待资源的进程队列。使用信号量进行通信时,通常需要如下步骤:创建信号量/信号量集或者获取系统中已有的信号量/信号量集;初始化信号量:早期信号量通常初始化为1,但有些进程一次需要多个同类的临界资源或多个不同类且唯一的临界资源,因此可能需要初始化信号量集;信号量的P、V操作:根据进程请求修改信号量的数量,P操作使信号量-1,V操作使信号量+1;从系统中删除不需要的信号量。

1.semget()函数:

        创建一个新的信号量集或获取一个已经存在的信号量集,该函数存在于sys/sem.h,其声明如下:

int semget(key_t key, int nsems, int semflg);

        参数:key是信号量的键值,通常为一个整数;nsems为创建的信号量数目;semflg为标志位,同open和msgget函数的标志位功能相似,用来设置权限(权限位可与IPC_CREAT及IPC_EXCL发生位或;IPC_PRIVATE:表示该信号量为当前进程的私有信号量。)

        返回值:成功返回信号量的标识符;不成功返回-1并设置errno( EACCES:表示进程无访问权限;ENOENT:表示传入的键值不存在;EINVAL:表示nsems小于0或信号量已达上限;EEXIST:当semflg设置为IPC_CREAT和IPC_EXCL时,该信号量已存在。)

2.semctl()函数:

        对信号量或信号量集进行控制。函数存在于sys/sem.h中,其声明如下:

int semctl(int semid, int semnum, int cmd, ...);

        参数:semid是信号量标识符,通常为semget函数的返回值;semnum是信号量在信号量集中的编号,该参数在使用信号量集时才会使用,通常设置为0,表示取第一个信号;cmd是对信号量进行操作,常用的设置为SETVAL和IPC_RMID:(SETVAL:表示semctl函数的功能为初始化信号量的值,信号量的值通过可选参数传入,信号量在使用前应先对其值进行设置;IPC_RMID:表示semctl函数的功能为删除指定信号量。信号量的删除应由其所有者或创建者进行,没有被删除的信号量将会一直存在于系统中。);最后一个参数是可选参数,依赖于参数cmd,使用该参数时,用户必须在程序自定义一个如下所示的共用体。

        返回值:成功根据参数cmd的取值返回相应信息,通常为一个非负整数;不成功返回-1并设置errno。

3.semop()函数:

改变信号量的值,函数存在于sys/sem.h中,其声明如下:

int semop(int semid, struct sembuf *sops, unsigned nsops);

        参数:semid是信号量标识符,通常为semget函数的返回值;sops是一个struct sembuf类型的数组指针,该数组中的每个元素设置了要对信号量集的哪个信号做哪种操作(sem_op = -1表示P操作;sem_op = +1表示V操作;通常设置sem_flag = SEM_UNDO:若进程退出前没有删除信号量,则信号量将会由系统自动释放。);nsops表示参数sops所指数组中元素的个数。

        返回值:成功返回0;不成功返回-1并设置errno。

三.共享内存:

        共享内存允许两个或多个进程访问给定的同一块存储区域。它是效率最高的一种进程通信方式,节省了不同进程间多次读写的时间;在写进程的操作尚未完成时,不应有进程从共享内存中读取数据。共享内存自身不限制对共享内存的读写次序,程序开发人员应自觉遵循读写规则;一般情况下,共享内存与信号量一起使用,由信号量帮它实现读写操作的同步。

1.shmget()函数:

        创建一个新的共享内存或打开一块已存在的共享内存,函数存在于sys/shm.h中,声明如下:

int shmget(key_t key, size_t size, int shmflg);

        参数:key是共享内存的键值,通常为一个整数;size用于设置共享内存的大小;shmflg用于设置shmget函数的创建条件(一般设置为IPC_CREAT或IPC_EXCL)及进程对共享内存的读写权限。

        返回值:成功返回共享内存的标识符,一个非负整数;不成功返回-1并设置errno。

2.shmat()函数:

        进行地址映射,将共享内存映射到进程虚拟地址空间中,存在于sys/shm.h中,声明如下:

void *shmat(int shmid, const void *shmaddr, int shmflg);

        参数:shmid是共享内标识符,通常为shmget函数的返回值;shmaddr用于指定共享内存映射到虚拟内存时的虚拟地址,设置为NULL时,映射地址由系统决定;shmflg用于设置共享内存的使用方式,如果shmflg = SHM_RDONLY,则共享内存将以只读的方式进行映射,当前进程只能从共享内存中读取数据。

        返回值:成功返回映射的地址并更改共享内存shmid_ds结构中的属性信息;不成功返回-1并设置errno。

3.shmdt()函数:

        解除物理内存与进程虚拟地址空间的映射关系,存在于sys/shm.h中,声明如下:

int shmdt(const void *shmaddr);

        参数:shmaddr表示 返回的虚拟空间地址。

        返回值:成功返回映射的地址并更改共享内存shmid_ds结构中的属性信息;不成功返回-1并设置errno。

4.shmctl()函数:

        对已存在的共享内存进行操作,具体的操作由参数确定,存在于sys/shm.h中,声明如下:

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

struct shmid_ds{
    struct ipc_perm shm_perm;            /* 操作权限*/
    size_t shm_segsz;                   /*段的大小(以字节为单位)*/
    time_t shm_atime;                      /*最后一个进程附加到该段的时间*/
    time_t shm_dtime;                      /*最后一个进程离开该段的时间*/
    time_t shm_ctime;                      /*最后一个进程修改该段的时间*/
    unsigned short shm_cpid;               /*创建该段进程的pid*/
    unsigned short shm_lpid;               /*在该段上操作的最后1个进程的pid*/
    short shm_nattch;                      /*当前附加到该段的进程的个数*/
    /*下面是私有的*/
    unsigned short shm_npages;          /*段的大小(以页为单位)*/
    unsigned long *shm_pages;           /*指向frames->SHMMAX的指针数组*/
    struct vm_area_struct *attaches;     /*对共享段的描述*/
};

        参数:shmid是共享内存标识符;cmd为要执行的操作,常用的设置为IPC_RMID,功能为删除共享内存;buf对共享内存的管理信息进行设置,该参数是结构体shmid_ds的指针。

        返回值:成功返回0;不成功返回-1并设置errno。

特殊说明:共享内存与消息队列、信号量相同,在使用完毕后都应该进行释放;调用fork函数创建子进程时,子进程会继承父进程已绑定的共享内存;调用exec函数更改子进程功能及调用exit函数时,子进程都会解除与共享内存的映射关系,因此在必要时仍应使用shmctl函数对共享内存进行删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值