进程间通信有五种方式:
第一种没学
第二种匿名管道
截取自linux0.11内核源码中的pipe系统调用
int sys_pipe(unsigned long * fildes)
{
struct m_inode * inode;
struct file * f[2];
int fd[2];
int i,j;
j=0;
for(i=0;j<2 && i<NR_FILE;i++)
if (!file_table[i].f_count)
(f[j++]=i+file_table)->f_count++;
/*上面那一段是在内核filetable中找出空闲的,然后将其计数加一,表示已被占用*/
if (j==1)
f[0]->f_count=0;
if (j<2)
return -1;
j=0;
/*如果没有找到两个就进行清除并返回-1*/
for(i=0;j<2 && i<NR_OPEN;i++)
if (!current->filp[i]) {
current->filp[ fd[j]=i ] = f[j];
j++;
}
/*从当前进程找两个空闲的file并将其指向内核的filetable*/
if (j==1)
current->filp[fd[0]]=NULL;
if (j<2) {
f[0]->f_count=f[1]->f_count=0;
return -1;
}
/*struct m_inode * get_pipe_inode(void)
{
struct m_inode * inode;
if (!(inode = get_empty_inode()))
return NULL;
if (!(inode->i_size=get_free_page())) {
inode->i_count = 0;
return NULL;
}
inode->i_count = 2;
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
///#define PIPE_HEAD(inode) ((inode).i_zone[0])
//#define PIPE_TAIL(inode) ((inode).i_zone[1])
inode->i_pipe = 1;
return inode;
***找一个空闲的inode,并对inode进行设置,我对inode也不是很了解,以后再进行补充***
}
*/
if (!(inode=get_pipe_inode())) {
current->filp[fd[0]] =
current->filp[fd[1]] = NULL;
f[0]->f_count = f[1]->f_count = 0;
return -1;
}
f[0]->f_inode = f[1]->f_inode = inode;
f[0]->f_pos = f[1]->f_pos = 0;
f[0]->f_mode = 1; /* read */
f[1]->f_mode = 2; /* write */
/*extern inline void put_fs_long(unsigned long val, unsigned long *addr);
extern inline 表示该函数是一个外部链接的内联函数,内联函数可以在调用点直接展开,而不需要像普通函数那样进行函数调用的开销。
内联汇编代码:
__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
__asm__ 是 GCC 和其他兼容的编译器用来嵌入汇编语言代码的关键字。
"movl %0,%%fs:%1" 是汇编指令,将 %0 寄存器中的值移动到 %fs 段寄存器偏移地址为 %1 处的内存位置。
%0 对应于 "r" (val),表示使用寄存器约束,将 val 的值加载到 %0 中。
%%fs:%1 对应于 "m" (*addr),表示将 addr 指针所指向的内存地址作为内存约束,即将 %0 中的值写入到 %fs 段寄存器的偏移地址为 %1 处的内存位置。*/
put_fs_long(fd[0],0+fildes);
put_fs_long(fd[1],1+fildes);
return 0;
}
看完上面代码,不太理解在使用管道时,将传输的信息保存在哪(就是内核的filetable不对应具体的文件,你在使用管道时,read和write的数据保存在哪),所以研究一下inode,还要分析read和write。
inode可以看linux文件系统综述
linux文件目录代码解析
目录也是一个文件,找到目录的i节点,读出对应的数据区的数据,数据是下一层目录的i节点的地址和对应的文件名字,这样一层层的套下去,直到找到匹配的文件。
第三种:有名管道
把匿名管道的内核文件结构体换成了具体的文件,这样你就可以不需要父子进程都可以访问这个文件。
第四种 共享内存
分三步
3.mmap();
mmap主要用来做内存映射的,可以将虚拟内存和磁盘上的文件直接映射。正常来说我们在写文件读文件的时候是需要使用系统调用api来进行,比如说read/write,这两个系统调用读写文件的方式是需要进行两次拷贝的,从用户空间拷贝到内核空间,然后从内核空间再拷贝到磁盘,而mmap将文件的地址直接映射到虚拟内存,这样,我们直接往这个地址读/写内容,可以像操作malloc申请出来的空间地址一样,写到这个地址,内容就直接在文件中了,减少了一次拷贝,提高了效率。这样一个公共的内存区域,也可以用来进程间通信
具体可以参考mmap()
第五种消息队列