【Linux】多进程编程
一、进程基础
- 进程:进程是操作系统的概念,每当我们执行一个程序时,对于操作系统来讲就创建了一个进程,在这个过程中,伴随着资源的分配和释放。可以认为进程是一个程序的一次执行过程。
- 进程与程序的区别:
- 程序时静态的,它是一些保存 在磁盘上得指令的有序集合,没有任何执行的概念。
- 进程是一个动态的概念,它是程序执行的过程,包括创建、调度和消亡。
- 进程在操作系统中的表示:task_struct, 进程由一个叫task_struct的结构体描述,也叫进程控制块PCB,也就是说linux中的每个进程对应一个task_struct结构体。该结构体记录了进程的一切。
- Linux进程中的文件:Linux操作系统中每个进程有两个数据结构描叙文件相关信息。
- 第一个:fs_struct,它包含此进程当前工作目录和根目录、umask。umask是新文件被 创建的缺省模式,它可以通过系统调用来改变。
- 第二个:files_struct,包含此进程正在使用的所有文件的信息。f_mode字段描述该文件是以什么模式创建的:只读、读写、还是只写。f_pos保存文件中下一个读或写将发生的位置。f_inode描叙文件的VFS索引节点,而f_ops是一个例程向量的指针,每个代表一个想施加于文件的操作的函数。
- 进程的运行时结构:(摘自Vamei博客,http://www.cnblogs.com/vamei/archive/2012/10/09/2715388.html)
- 查看进程信息:比如ps等命令
二、进程控制
Linux环境下,有两个基本的操作用于创建和修改进程:函数fork()用来创建一个新的进程,该进程几乎是当前进程的一个完全拷贝;函数族exec()用来启动另外的进程以取代当前运行的进程。
2.1 fork系统调用
定义如下:
#include<sys/types.h> #include<unistd.h> pid_t fork(void);该函数的调用返回两次,在父进程中返回的是子进程的PID,在子进程返回的是0,根据此来判断当前进程是父进程还是子进程。fork调用失败时,返回-1.并设置errno。
fork函数复制当前进程,在task_struct中创建新的进程表项,很多属性复制自父进程,采用“写时复制”的技术,同时,父进程中打开的文件描述符在子进程中也是打开的,计数器加1.
示例代码:来自http://blog.csdn.net/jason314/article/details/5640969
/* * fork_test.c * version 1 * Created on: 2010-5-29 * Author: wangth */ #include <unistd.h> #include <stdio.h> int main () { pid_t fpid; //fpid表示fork函数返回的值 int count=0; fpid=fork(); if (fpid < 0) printf("error in fork!"); else if (fpid == 0) { printf("i am the child process, my process id is %d/n",getpid()); printf("我是爹的儿子/n");//对某些人来说中文看着更直白。 count++; } else { printf("i am the parent process, my process id is %d/n",getpid()); printf("我是孩子他爹/n"); count++; } printf("统计结果是: %d/n",count); return 0; }2.2 exec函数族
系统调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量(envp)。exec函数族当然不止一个,但它们大致相同,在Linux中,它们分别是:execl,execlp,execle,execv,execve和execvp。
一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。
那么如果我的程序想启动另一程序的执行但自己仍想继续运行的话,怎么办呢?那就是结合fork与exec的使用。下面一段代码显示如何启动运行其它程序:
示例:
char command[256]; void main() { int rtn; /*子进程的返回数值*/ while(1) { /* 从终端读取要执行的命令 */ printf( ">" ); fgets( command, 256, stdin ); command[strlen(command)-1] = 0; if ( fork() == 0 ) { /* 子进程执行此命令 */ execlp( command, command ); /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/ perror( command ); exit( errorno ); } else { /* 父进程, 等待子进程结束,并打印子进程的返回值 */ wait ( &rtn ); printf( " child process return %d/n",. rtn ); } } }
三、进程通信
我们知道多,进程间的地址空间相对独立。进程与进程间不能像线程间通过全局变量通信。 如果想进程间通信,就需要其他机制。
常用的进程间通信方式有这几种
- 传统的进程间通信方式:无名管道(pipe)、有名管道(fifo)和信号(signal)
- System v IPC对象:共享内存(share memory)、消息队列(message queue)和信号灯(semaphore)
- BSD:套接字(socket)
3.1 管道通信
管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,而fd[1]固定用于写管道,一般文件I/O的函数都可以用来操作管道(lseek除外)。
示例:父进程向管道中写数据,子进程从管道中读取数据“hello world”
#include <fcntl.h> #include <stdio.h> #include "apue.h" #include <errno.h> #include <sys/wait.h> #include <sys/types.h> #include <unistd.h> #include <stropts.h> #include <sys/mman.h> int main(int argc , char *argv[]) { int n,fd[2]; pid_t pid; char line[MAXLINE]; if(pipe(fd)<0) err_sys("pipe err"); if((pid=fork())<0) err_sys("pipe erro"); else if(pid>0) { close(fd[0]); if(write(fd[1],"hello world \n",13)<0) err_sys("write err"); } else{ close(fd[1]); if((n=read(fd[0],line,MAXLINE))<0) err_sys("read erro"); if(write(STDOUT_FILENO,line,n)<0) err_sys("write erro"); } exit(0); }3.2 信号量
推荐博客:http://blog.chinaunix.net/uid-26833883-id-3228615.html
3.3 共享内存
推荐博客:http://blog.chinaunix.net/uid-26833883-id-3230564.html
共享内存的介绍:
- 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。
- 为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间。进程就可以直接读写这一块内存而不需要进行数据的拷贝,从而大大提高效率。
- 由于多个进程共享一段内存,因此也需要依靠某种同步机制。
操作流程:
<1>创建/打开共享内存
<2>映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
<3>撤销共享内存映射
<4>删除共享内存对象
相关API:shmget,shmat,shmd,shmctl.
3.4 消息队列
四、参考
进程基础 http://www.cnblogs.com/vamei/archive/2012/10/09/2715388.html
从程序到进程 http://www.cnblogs.com/vamei/archive/2012/09/20/2694466.html
进程间管道通信 http://blog.chinaunix.net/uid-26833883-id-3227144.html
作者:西芒xiaoP
出处:http://www.cnblogs.com/panweishadow/
若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。