文章目录
- 1、消息队列
- 2、信号量
- 1、了解概念
- 2、信号量理解
- 3、接口
- 4、理解IPC
1、消息队列
两个进程ab之间系统维护一个队列结构,a进程往队列里放信息,信息编号为1,b进程往队列里放信息,信息编号为2;之后开始读取数据的时候,a就会读2的数据,b就会读1的数据。系统中有很多很多的消息队列,系统就会建立一个结构体来管理这些数据。
创建一个消息队列的接口是msgget
masflg参数就是IPC_CREAT IPC _EXCL, key之前写过,在这里就是一个共享内存的号。查看命令ipcs -q,删除ipcrm -q。接口删除则是这样
用man来查看。消息队列有msgsnd, msgrcv发送和接受接口。消息队列发送的消息是一个结构体类型,一个long变量,一个柔性数组,数组是要发的消息,long变量则是数据类型
消息队列是比较老旧的知识,不推荐使用,用起来也不是很舒服,完全有更好的通信方案使用。
2、信号量
1、了解概念
所有人都能看到的资源是公共资源,为了保护这个资源,系统在任何一个时刻,都只允许一个进程在进行共享资源的访问,这个就是互斥。
对于任何一个时刻,都只允许一个执行流在进行访问的共享资源叫做临界资源。比如管道。
临界资源是通过代码访问的,凡是访问临界资源的代码的区域,叫做临界区。
原子性是指要么做要么做完的两种确定状态的属性。
2、信号量理解
信号量也叫信号灯,它相当于一个计数器count,用来描述资源数量,这个资源就是临界区里可以存储的资源。任何一个执行流,想访问临界资源中的一个子资源的时候,不能直接访问,需要先申请信号量资源,也就是看看临界区里还有多少可以存储的位置,申请成功一个count就减1,;当离开临界区时,就要释放对应的临界资源,count就是加1。如果count为0,申请信号量这个进程就会被挂起。count一直为0,进程就一直阻塞,知道count又大于0。
每一个进程都会在进入临界区之前申请信号量,出去时释放信号量。
无论进程都需要先看到信号量才行。系统把信号量做成一个共享资源,信号量的+±-也具有原子性。
申请信号量资源当作P操作,释放信号量资源当作V操作,信号量的相关操作其实就是PV操作。
由于进程需要看到同一个计数器资源,所以信号量被归类到了进程间通信。
如果计数器是1,当有一个进程申请好信号量资源,count减为0后,其它进程就无法拿到资源,这就形成了一个二元信号量,也就是一个互斥功能。
3、接口
semget接口,它有key,semflg参数,semflg有两个选项IPC_CREAT IPC_EXCL,但中间还有一个参数nsems,这个参数的意思就是信号量的个数,也就是说一个进程可以一次性申请多个信号量,查看信号量就是ipcs -s,杀掉信号量就是ipcrm -s + 信号量编号。
semctl接口也可以用来删除,semctl接口有semnum的参数,代表要对哪一个信号量进行操作,cmd参数则是对应一些选项,而它还有其他参数,是一些可变参数,用man查看会看到更多详细信息。
semop接口则是操作信号量,参数中semid表示要操作的信号量;struct sembuf* sops参数是一个需要显式定义的结构体,里面要有哪个信号量,要做的操作,flag则是有一些自己的选项,可以选默认。
4、理解IPC
共享内存有自己的数据结构。
这是用户层可以看到的数据结构,系统底层有更多的信息,它只是给了用户可以看到的信息。
信号量,共享内存,消息队列的结构体中有很多共同点,比如第一个变量struct ipc_perm shm/sem/msg_perm。
系统会定义一个数组,放的就是struct ipc_perm* ipc_id_arr[]类型的,所以是一个指针数组,其中的元素指向struct ipc_perm类型的变量,也就是像信号量等结构体的第一个变量,指向第一个也就指向了整个结构体。所以这样就可以将内核中的所有ipc资源统一以数组的方式进行管理。如果想访问共享内存的其它元素,那就把这个数组强制转换类型成共享内存的结构体类型就好了。这对于系统是可以优化好的。
上面写的perm变量是什么?其实就是多态。信号量,消息队列结构体中的这个变量就是基类,指针数组的元素指向一个子类对象,就使用了对应的perm。