多进程编程

来源:互联网 发布:js 数组是否包含字符串 编辑:程序博客网 时间:2024/05/22 23:01

1.fork调用

pid_t fork();
这个函数的每次调用都会返回两次,在父进程中返回子进程的pid,在子进程中返回0;失败返回-1;
fork在复制的时候,在内核进程中创建一个新的进程表项,新的表项很多东西和原来的进程是相同的,比如:堆指针、栈指针、标识寄存器的值。但是也有很多属性是不相同的,例如PPID,信号位图被清除。
子进程的代码和源代码完全相同,它复制了父进程的数据(堆数据、栈数据、静态数据)。数据的复制采用的是写时拷贝技术
此外父进程打开的文件描述符在子进程中也是打开的,且文件文件描述符的引用计数加1,不仅如此,父进程的根目当前工作目录等变量的引用计数都加1.

2.exec

int execl(const char * path,const char * arg , ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg,... ,char *const envp[] );int execv(const char *path , char *const argv[]);int execvp(const char *file,char *const argv[]);int execve(const char *path,char *const argv[],char *const envp[]);

path :参数指定可执行文件的完整路径,file参数可以接受文件名,该文件的具体位置则在环境变量PATH中搜索,arg接受可变参数。agv则接受参数数组,他们都会被传递给行的程序的main函数。envp参数用于设置新程序的环境变量。如果未设置它,则新程序将使用全局变量environ指定环境变量。
一般来说exec是不返回,如果不出错原来的代码是不会被执行的,因为原来的代码被全部替代。

3.处理僵尸进程

僵尸进程:当父子进程在运行时,子进程先于父进程结束。子进程结束后,父进程还没有读取他的退出状态之前。
孤儿进程:当父进程先于子进程结束,子进程的pid没有被释放,我们init将接管该子进程。
如果父进程没有正确的处理子进程的返回信息,子进程处于僵尸态,并占据这内核资源,内核资源有限。
方法一:在父进程中调用wait和waitpid函数,等待子进程结束,获取子进程的信息。从而避免了僵尸进程的发生。pid_t wait( int *stat_loc); pid_t waitpid(pid_t pid,int *stat_loc , int options);
wait函数将阻塞进程,直到进程的某个子进程结束运行为止,他将返回结束进程的pid。wait一直等待,处于阻塞状态,他不是我们所希望的,waitpid刚好克服这个,他就是一直等到一个指定的pid。如果子进程正常退出就返回他的pid,否则返回-1;

4.管道

管道用于父子进程间传递数据,利用的fork调用之后两个管道文件描述符都保持打开,一对这样的文件描述符只能保证父子进程间一个方向传递数据。
这里写图片描述
如果父子进程需要双向传递,我们必须要两个管道,有个socketpair建立一个全双工管道。

5.信号量

5.1 信号量原语
当我们当问同一块资源的时候,我们需要考虑同步的问题。以确保在同一时间之内只有一个进程访问一块资源。我们通常会遇到的代码访问时间很短,但是这段代码,就是临界区。
为了处理竞态条件,去两个操作P、V操作。
P操作:若资源数大于0,就减一;如果为0,则挂起进程的执行;
v操作:如果有进程因为等待这个资源而被挂起,那么就唤醒这个进程;如果没有就给资源数加1;

原创粉丝点击