博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
APUE 学习笔记(十) 高级I/O
阅读量:5156 次
发布时间:2019-06-13

本文共 4651 字,大约阅读时间需要 15 分钟。

1. Unix IPC(InterProcess Communication)

同一主机的各个进程间的IPC:管道、FIFO、消息队列、信号量、共享存储器
不同主机上的各个进程间IPC:socket套接字
 

2. 管道

管道进行IPC有两个局限:
(1) 半双工,即
数据只能在一个方向上流动
(2) 只能在
具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用fork,此后 父子进程之间可以使用该管道
 
fstat函数对管道的每一端都返回一个FIFO类型的文件描述符,可以用S_ISFIFO宏来测试管道
 
通常是一个进程调用pipe函数创建管道,紧接着调用fork,这样就创建了从父进程到子进程的IPC通道
 
对于从父进程到子进程的管道,
父进程关闭 管道的读端(fd[0])子进程关闭管道的写端(fd[1])
 
popen、pclose两个函数实现的操作是:创建一个管道,调用fork产生一个子进程,关闭管道的不使用端,执行一个shell以运行命令,最后等待命令终止
 
#include 
FILE* popen(const char* cmdstring, const char* type);int pclose(FILE* fp);

函数popen先执行fork,然后调用exec以执行cmdstring,并且返回一个标准I/O文件指针

 

  

type为“r”表示可读,为“w”表示可写
 
简单实现一个popen:
1 #include 
2 #include
3 #include
4 #include
5 #include
6 7 /* pointer to array allocated at run-time */ 8 static pid_t* childpid = NULL; 9 10 /* from our open_max() */11 static int maxfd;12 13 FILE* my_popen(const char* cmdstring, const char* type)14 {15 int pfd[2];16 pid_t pid;17 18 /* only allow type = "r" or "w" */19 if ((type[0] != 'r' && type[0] != 'w') || type[1] != 0) {20 errno = EINVAL;21 return NULL;22 }23 childpid = (pid_t*)calloc(maxfd, sizeof(pid_t));24 if (childpid == NULL) {25 return NULL;26 }27 }28 29 if (pipe(pfd) < 0) {30 return NULL;31 }32 33 if ((pid = fork()) < 0) {34 return NULL;35 } else if (pid == 0) { /* child */36 if (*type == 'r') {37 close(pfd[0]);38 if (pfd[1] != STDOUT_FILENO) {39 dup2(pfd[1], STDOUT_FILENO);40 close(pfd[1]);41 }42 } else {43 close(pfd[1]);44 if (pfd[0] != STDIN_FILENO) {45 dup2(pfd[0], STDIN_FILENO);46 close(pfd[0]);47 }48 }49 50 /* close all fds in childpid[] */51 for (int i = 0; i < maxfd; ++i) {52 if (childpid[i] > 0) {53 close(i);54 }55 }56 57 }58 59 /* parent continue */60 FILE* fp;61 if (*type == 'r') {62 close(pfd[1]);63 if ((fp = fdopen(pfd[0], type)) == NULL) {64 return NULL;65 }66 } else {67 close(pfd[0]);68 if ((fp = fdopen(pfd[1], type)) == NULL) {69 return NULL;70 close(pfd[0]);71 if ((fp = fdopen(pfd[1], type)) == NULL) {72 return NULL;73 }74 }75 76 childpid[fileno(fp)] = pid;77 return fp;78 }
 

3. 消息队列

消息队列是消息的链接表,存放在内核中并由消息队列ID标识
msgget用于创建一个新队列或打开一个现存的队列
msgsnd将新消息添加到队列尾端
msgrcv用户从队列中取消息
 

4. 信号量

信号量是一个计数器,用于多进程对共享数据对象的访问
 

5. 共享存储器

共享存储器允许多个进程共享一个给定的存储区,因为
数据不需要在客户进程和服务器进程之间复制,所以这是最快的IPC
使用共享存储区时必须确保 多个进程之间对给定的存储区的同步访问,通常,
信号量被用来实现对共享存储区的同步访问
#include 
/* 获得共享存储标识符 */int shmget(key_t key, size_t size, int flag);/* 对共享存储区执行多种操作 */int shmctl(int shmid, int cmd, struct shmid_ds* buf);/* 进程将共享存储区连接到它的地址空间中 */void* shmat(int shmid, const void* addr, int flag);

如果addr为0,则此段连接到内核选择的第一个可用地址上。一般将addr指定为0,以便由内核选择地址

打印各种不同类型的数据所存放的位置:

1 #include 
2 #include
3 #include
4 #include
5 6 #define ARRAY_SIZE 40000 7 #define MALLOC_SIZE 100000 8 #define SHM_SIZE 100000 9 #define SHM_MODE 0600 /* user read/write */10 11 char array[ARRAY_SIZE]; /* uninitialized data = bss */12 13 int main(int argc, char* argv[])14 {15 int shmid;16 char* ptr = NULL;17 char* shmptr = NULL;18 19 fprintf(stdout, "array[] from %p to %p\n", array, array + ARRAY_SIZE);20 fprintf(stdout, "stack around %p\n", &shmid);21 ptr = (char*)malloc(MALLOC_SIZE);22 if (ptr == NULL) {23 fprintf(stderr, "malloc error\n");24 }25 26 fprintf(stdout, "malloc from %p to %p\n", ptr, ptr + MALLOC_SIZE);27 28 shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE);29 if (shmid < 0) {30 fprintf(stderr, "shmget error\n");31 }32 33 shmptr = shmat(shmid, 0, 0);34 if (shmptr == (void*)-1) {35 fprintf(stderr, "shmat error\n");36 }37 38 fprintf(stdout, "shared memory from %p to %p\n", shmptr, shmptr + SHM_SIZE);39 if (shmctl(shmid, IPC_RMID, 0) < 0) {40 fprintf(stderr, "shmctl error\n");41 }42 free(ptr);43 return 0;44 }

在基于Intel的Linux系统上运行此程序,其输出如下:

 

 

如果mmap函数指定了 MAP_SHARED标志,则此存储映射区可被多个进程共享
匿名存储映射:调用mmap时指定MAP_ANON标志,并将
文件描述符指定为-1,结果得到的映射区域是匿名的,因为并不与一个文件描述符相关联

转载于:https://www.cnblogs.com/wwwjieo0/p/3739107.html

你可能感兴趣的文章
Java中的日期和时间
查看>>
Django基于admin的stark组件创建(一)
查看>>
批处理/DOS命令删除文件夹下某类型的文件
查看>>
模板 - 数学 - 矩阵快速幂
查看>>
优秀的持久层框架Mybatis,连接数据库快人一步
查看>>
PAT L2-016 愿天下有情人都是失散多年的兄妹
查看>>
抛弃IIS,利用FastCGI让Asp.net与Nginx在一起
查看>>
C. Tanya and Toys_模拟
查看>>
使用SwingWork反而阻塞SwingUI
查看>>
Windchill中如何扩展字段长度?
查看>>
pytorch中的forward前向传播机制
查看>>
课后作业-阅读任务-阅读提问-4
查看>>
Delphi 深入浅出VCL(2)-TObject所有对象的根
查看>>
配置IIS虚拟目录遇到的5个问题
查看>>
2-03顺序表的操作
查看>>
耿丹CS16-2班第一次作业汇总
查看>>
查看mysql表大小
查看>>
命令行程序测试自动化
查看>>
My Blog
查看>>
array_reduce() 与 array_map()
查看>>