您的位置:首页 > 运维架构 > Linux

Linux进程通信

2016-10-03 22:30 204 查看
进程控制原理
进程和程序区别:程序在运行的时候叫做进程,程序是静态的,进程是动态的。
进程特点:动态性、并发性、独立性、异步性。
进程三态:就绪、(经进程调度)执行、阻塞。
进程ID(PID):标识进程的唯一数字,父进程(在当前进程创建一个新的进程,该进程称为子进程,创建的称为父进程)ID(PPID),启动进程的用户ID(UID)。
进程互斥:若干进程都要使用某一共享资源时(硬件、软件),任何时刻只允许一个进程访问,该资源称为临界资源。进程中访问该临界资源的程序称为临界区。
进程同步:一组进程按一定的顺序执行的过程。
进程调度:按一定算法,从一组待运行的进程中选出一个来占用CPU。方法分:抢占式调度和非抢占式。
调度算法:先来先服务,短进程优先调度,高优先级优先调度(不同的系统有可能优先级数字高低对应不同的优先级),时间片轮转法。
死锁:多个进程因竞争资源而形成一种僵局,若无外力作用,这些进程永远无法推动。

获取ID:
#include<sys/types.h>
#include<unistd.h>
pid_t getpid(void)//获取本进程ID
pid_t getppid(void)//获取父进程ID

进程创建:
#include<unistd.h>
pid_t fork(void)//创建子进程
eg:

#include<sys/types.h>
#include<unistd.h>
main()
{
pid_t pid;
//此时仅有一个进程
pid=fork();//有两个返回值, 父进程返回的是子进程的ID,子进程返回的是0.
//此时已经有两个进程在同时运行
if(pid<0)
printf("error in fork!");
else if(pid==0)
printf("i am the child process,ID is %d\n",getpid());
else
printf("i am the parent process,ID is %d\n",getpid());
}

运行后两条语句同时被打印出来。
子进程和父进程代码段共享,数据段会拷贝到子进程中。
pid_t vfork(void);//创建子进程
fork与vfork的区别:(1)fork的父和子进程执行次序不确定,vfork是子先运行。
(2)fork子拷贝父的数据段,而vfork子共享父的数据段。

exec函数族:启动一个新的程序,替换原有的进程,此进程的PID不会改变。

   (1)int execl(const char *path,const char *arg1,...)
path:被执行程序名,arg1-argn:被执行程序命令行参数,含程序名,以空指针NULL结束。

#include<unistd.h>
main()
{
execl("/bin/ls","ls","-al","/etc/passwd",(char *)0);
}

   (2)int execlp(const char *path,const char *arg1,...)

      与execl区别:execlp的path表示被执行程序名,不含路径,路径会从path这个环境变量中查找。

  (3)int execv(const char *path,char *const argv[ ])
path:被执行程序名(含路径),argv[]:被执行程序命令行参数数组。

  (4)int system(const char *string):调用fork产生子进程,由子进程来调用/bin/sh -c string来执行参数string所代表的命令。

进程等待:阻塞该进程,直到某个子进程退出
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status)
eg:wait(NULL);//等待子进程退出
pid_t waitpid(pid_t pid,int *status,int options)//与wait函数类似。
//pid>0时,只等待进程ID等于pid的子进程,pid=-1时,等待任何一个子进程退出,没有任何限制,pid=0时,等待同一个进程组中的任何子进程,pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,如果我们不想使用它们,也可以把options设为0。

进程通信概述:

为什么通信:数据传输
 资源共享
 通知事件(一个进程向另一个或一组发送消息,通知他们发生了某事件。如进程同步)

   进程控制(有些进程希望完全控制另一个进程的执行)

通信方式:管道(pipe)和有名管道(FIFO)
信号(signal)
消息队列
共享内存
信号量
套接字(socket)

管道通讯:管道是单向的,先入先出的。它把一个进程的输出和另一个进程的输入链接在一起。
无名管道只用于父进程和子进程间通信,有名管道是任意两个都可以。

   (1)无名:int pipe(int filedis[2]);//当管道建立时,会创建两个文件描述符。filedis[0]用于读,filedis[1]用于写。关闭管道只需用close将文件描述符关闭即可。
管道读写:通常先创建管道,再通过fork函数创建子进程,该子进程会继承父进程的所创建的管道。
注意:必须在调用fork之前创建管道。
//eg:pipe_rw.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
int main()
{
int pipe_fd[2];
pip_t pid;
char buf_r[100];
char *p_wbuf;
int r_num;

memset(buf_r,0,sizeof(buf_r));
if(pipe(pipe_fd)<0)
{
printf("pipe create error\n");
return -1;
}
//创建管道
if((pid=fork())==0)
{
printf("\n");
close(pipe_fd[1]);
sleep(2);//先睡眠一下,让出cpu给父进程写数据
if((r_num=read(pipe_fd[0],buf_r,100))>0)
{
printf("%d numbers read from the pipe is %s",);
}
close(pipe_fd[0]);
exit(0);
}
else if(pid>0)
{
close(pipe_fd[0]);
if(write(pipe_fd[1],"hello",5)!=-1)
{printf("parent write1 hello!\n");
}
if(write(pipe_fd[1],"pipe",5)!=-1)
{printf("parent write2 pipe!\n");
}
close(pipe_fd[1]);
sleep(3);
waitpid(pid,NULL,O);
exit(0);
}
return 0;
}
(2)命名管道
创建:#include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char* pathname,mode_t mode)//pathname:FIFO文件名,mode(属性,和文件章节一样)。
当打开FIFO时,非阻塞标志O_NONBLOCK对读写的影响:

        1.没有使用0_NONBLOCK,如试图读取空的FIFO,将导致进程阻塞。
2.使用O_NONCLOCK,出现阻塞,立刻出错返回。errno是ENXIO。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: