linux进程间通信学习


最近学习了linux进程间通信,写下些心得。

(1)管道通信;pipe(p_fd[])创建管道,fd[0]用于读,fd[1]用于写,这是有亲缘关系的管道做法,也就是在不同进程间具有亲子关系,没有读管道的存在,写管道讲不再有意义,向管道中写入数据的进程将受到内核传来的SIFPIPE信号,应用程序可以处理也可以忽略。写管道不具有原子性,也就说当管道缓冲区具有空闲区域时,写进程将会试图往管道中写入数据,读进程不读出数据,将会是写进程一直阻塞。我们可以用read,write来读取。

除了管道意外,还可以用popen,pclose函数来代替。popen先fork,然后再exec执行参数cmdstring,一般是shell文件的命令,返回一个文件指针,再根据参数type来决定,如果是可读的,将文件指针定位到cmdstring的标准输出,如果是可写的,则定位到标准输入。比如popen(cmd,w)再通过fget(buf,size,stdin)来输入信息。

命名管道用来描述没有亲缘关系的管道,也成为fifo管道。int mkfifo(const char *pathname, mode_t mode)pathname是创建成功以后的管道名,管道仅需要创建而不需要打开,因为使用它们的进程通过继承获得了管道的文件描述符,命名管道与进程没有关系,使用open函数打开,再使用write,read进行操作。

(2)内存映射;允许不同的进程之间通过共享的文件进行通信,内存映射不同于共享内存,内存映射在文件和进程间建立起了关系,linux把被映射的文件分成许多页块,然后复制它们进程的虚存页,通过进程的虚地访问文件的内存。每次需要访问的时候都使用mmap函数,返回的空指针是你设置好的数据结构,比如往内存中写入一定数据结构的数据,那么先mmap这个文件,然后往这个指向共享内存的指针写入数据,操作完毕后解除文件映射,使用munmap函数,将内存中的数据写入磁盘,另一进程使用mmap函数访问这个磁盘,映射到内存,取出数据。有亲缘关系的进程则不需要再次映射。

(3)消息队列;消息队列是消息的链表,有唯一的id号存在内核中,所以每创建一个消息队列都需要唯一的key,生成key的是key_t ftok(char *pathname, int proid),proid为项目的id,也可以理解为序列号,必须是非0的整数,这个key是用来获取IPC对象的标示符(ID),先生成key,再用函数msgget创建或返回参数key对应队列的标示符,int msgget(key, msgflag),msgsnd函数发送一个消息到有msgid标示所对应的消息队列中,msgrcv从消息队列中取数据,msgctl函数对队列进行各种控制操作,msgid_ds,是队列结构,可用于删除时,msgid_ds不需要参数。

(4)共享内存;共享内存是内存块方式的数据段,其长度为系统参数限制内任意长度,对它的访问与通常的数组类似,不具备锁机制,所以最好结合信号灯以保证数据的一致性。先生成key,在创建共享内存,shmget,再使用函数shmat把shmid标示符的共享内存连接到调用进程的整数段中。参数shmaddr设置为0标示进程内数据段的地址由系统选择。shmdt接触共享内存与调用进程数据段的联系。shmctl对共享内存进行各种控制操作。

(5)信号量;对共享资源的限制机制,当申请资源时,信号量减一,当释放资源时,信号量加一,创建key,创建信号集,semget,再创建信号量,sebuf,sebuf决定了semop的自动具体操作,就是加1,减一的自动操作,所以一般有两个信号量,一个用来加1,一个用来减1,通过semop函数进行操作,使用while表示申请或释放资源中,semctl可用于删除信号灯。在对资源进行操作时,semop()...semop()完成。

另外的一种方法是socket,这个留到socket篇再讲。

你可能感兴趣的:(linux进程间通信学习)