10.1 进程间通信

  进程间通信的分类:

    文件

    文件锁

    管道和匿名管道FIFO

    信号

    消息队列

    共享内存

    信号量

    互斥量

    条件变量

    读写锁

    套接字

两个进程同时向管道中写数据,内核要保证它们是原子的,内核按照页做限制。

进程间共享信息的三种方式:一个通过文件系统,一个通过内核,一个在应用空间

 

IPC对象的持续性:

  随进程持续:一直存在,直到打开的最后一个进程结束。(如pipe和FIFO)

  随内核持续:一直存在,直到内核自举或者显式删除。(如System V消息队列、共享内存、信号量)

  随文件系统持续:一直存在,直到显式删除,即使内核自举还存在。(POSIX消息队列、共享内存、信号量(如果是使用映射文件来实现))

 查看系统的IPC对象以及它们的一些属性可以使用ipcs命令,如下:

 

其中key表示键,semid表示这个对象的id,owner表示拥有者。共享内存还有个属性是nattch,表示有多少个人连接上共享内存了。

ipcs -l可以查看IPC对象的一些系统限制:

 

 

消息队列提供了从一个进程向另一个进程发送一块数据的方法

每个数据块都有一个类型,接收者进程接收的数据块可以有不同的类型值

消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)。

管道是基于数据流的,先进先出。

消息队列是有边界的,可以后进先出。

消息队列有如下三个限制:

cat  /proc/sys/kernel/msgmax      最大消息长度限制

cat  /proc/sys/kernel/msgmnb      消息队列总的字节数

cat  /proc/sys/kernel/msgmni        消息条目数

 使用man 2 msgctl可以查看消息队列的一些数据结构:

struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in
queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages
in queue */
msglen_t msg_qbytes; /* Maximum number of bytes
allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};

struct ipc_perm {
key_t __key; /* Key supplied to msgget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */
unsigned short __seq; /* Sequence number */
};

消息队列在内核中的表示如下:

msq_ids存储了消息的一些元信息,具体的消息由内核来管理。

消息队列相关的一些API函数:

msgget函数原型如下:

  int msgget(key_t key,  int  msgflg)

  功能:用来创建和访问一个消息队列

  参数:

    key表示某个消息队列的名字

    msgflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的

  返回值:成功返回一个非负整数,即该消息队列的标识码;失败返回-1

 编写如下的msgget测试函数:

 1 #include <sys/types.h>
 2 #include <unistd.h>
 3 #include <stdio.h>
 4 #include <string.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <sys/msg.h>
 8 
 9 int main()
10 {
11     int msgid;
12     
13     msgid = msgget(0x1234, 0666);
14     if(msgid < 0)
15     {
16         perror("msgget error");
17         exit(0);
18     }
19     
20     return 0;
21 }

这段程序代表打开一个消息队列,执行结果如下:

系统中没有key值为0x1234的消息队列,所以出错返回。我们可以根据errno错误码进行更精确的控制。

我们修改msgget函数的第二个参数,程序如下:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/msg.h>

int main()
{
    int msgid;
    
    msgid = msgget(0x1234, 0666 | IPC_CREAT);
    if(msgid < 0)
    {
        perror("msgget error");
        exit(0);
    }
    
    printf("create msg queue success\n");
    
    return 0;
}

现在的参数表示,如果这个消息队列存在就打开旧的,如果不存在就创建新的。

现在我们的系统中是没有消息队列的,执行结果如下:

使用ipcs查看系统中的消息队列如下:

可以看到确实出现了一个key值为0x1234的消息队列IPC对象。

猜你喜欢

转载自www.cnblogs.com/wanmeishenghuo/p/9425001.html