2014025673《嵌入式系统程序设计》第七周学习总结
2014025673《嵌入式系统程序设计》第七周学习总结
在本周,主要学习了管道及消息队列等相关知识。
一、FIFO
1.有名管道和无名管道的区别:
- 无名管道:只能用于具有亲缘关系的进程之间。
- 有名管道:突破了无名管道的限制,它可以使互不相关的两个进程实现彼此通信,在建立管道之后,两个进程就可以像普通文件进行读写操作一样进行操作。
2.阻塞打开和非阻塞打开的读写。
(1)对于读进程。
- 若该管道是阻塞打开,且当前FIFO 内没有数据,则对读进程而言将一直阻塞到有数据写入。
- 若该管道是非阻塞打开,则不论FIFO 内是否有数据,读进程都会立即执行读操作。即如果FIFO内没有数据,则读函数将立刻返回0。
(2)对于写进程。
- 若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。
- 若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败。
二、mkfifo()函数
mkfifo函数的作用是在文件系统中创建一个文件,该文件用于提供FIFO功能,即实名管道。
- 相关函数
pipe popen open umask
- 函数头文件
#include <sys/types.h>
#include <sys/state.h>
- 函数原型
int mkfifo(const char *filename,mode_t mode)
- 函数传入值
- filename:要创建的管道
- 函数传入值 mode:
O_RDONLY | 读管道 |
O_WRONLY | 写管道 |
O_RDWR | 读写管道 |
O_NONBLOCK | 非阻塞 |
O_CREAT | 如果该文件不存在,那么就创建一个新的文件,并用第三个参数为其设置权限 |
O_EXCL | 如果使用O_CREAT 时文件存在,那么可返回错误消息。这一参数可测试文件是否存在 |
- 函数返回值
成功:0; 出错:-1; - 函数说明
mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此 umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开 FIFO文件时,O_NONBLOCK旗标会有影响
1.当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
2.没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
access()
- 功能:检查某个文件的存取方式。
- 原型:
int access(const char *filename, int mode)
- 参数:
- filename要检查的管道路径及名字
- mode要判断的模式
- R_OK只判断是否有读权限
- W_OK只判断是否有写权限
- X_OK判断是否有执行权限
- F_OK只判断是否存在
- 返回值:
0:指定的存取方式有效;-1:指定的存取方式无效 - 实际操作:
实际操作的实验过程下实验楼中进行,在进行实际操作时,要同时打开两个终端进行试验。
消息队列的应用
一、函数介绍
消息队列的实现包括创建或打开消息队列msgget()、添加消息msgsnd()、读取消息msgrcv()和控制消息队列msgctl()这4 种操作。
二、具体函数要点
1.msgget()函数
所需头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型
int msgget(key_t key, int msgflg)
函数传入值
key:消息队列的键值,多个进程可以通过它访问同一个消息队列,其中有
个特殊值IPC_PRIVATE。它用于创建当前进程的私有消息队列
函数返回值
成功:消息队列ID 出错:-1
2.msgsnd()函数
所需头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
函数传入值
msqid:消息队列的队列ID
msgp:指向消息结构的指针。该消息结构msgbuf 通常为:
struct msgbuf
{
long mtype; /* 消息类型,该结构必须从这个域开始 */
char mtext[1]; /* 消息正文 */
}
函数返回值
成功:0;出错:-1
3.msgrcv()函数
所需头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型:
int msgrcv(int msgid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)
函数传入值
msqid:消息队列的队列ID
msgp:消息缓冲区, 同于msgsnd()函数的msgp
msgsz:消息正文的字节数(不包括消息类型指针变量)
msgtyp:
等于0:接收消息队列中第一个消息
大于0:接收消息队列中第一个类型为msgtyp 的消息
小于0:接收消息队列中第一个类型值不小于msgtyp 绝对值且类型值又最小的消息
函数返回值
成功:0
出错:-1
4.msgctl()函数
所需头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型
int msgctl (int msgqid, int cmd, struct msqid_ds *buf )
函数传入值
msqid:消息队列的队列ID
命令参数
IPC_STAT:读取消息队列的数据结构msqid_ds,并将其存储在
buf 指定的地址中
IPC_SET:设置消息队列的数据结构msqid_ds 中的ipc_perm 域(IPC 操作权限描述结构)值。这个值取自buf 参数
IPC_RMID:从系统内核中删除消息队列
buf:描述消息队列的msgqid_ds 结构类型变量
函数返回值
成功:0;出错:-1
思想与感悟:
通过课上的学习的课下的练习,掌握了有名管道和无名管道的区别,体会了两个进程间传输。在消息队列部分,体会了消息队列和管道传输之间的区别,消息队列相对于管道传输更加灵活和方便。