Linux下多进程编程(C语言)

Linux下多进程编程(C语言)

一、进程简介

1、进程是程序的执行。程序是静态的,进程是动态的。
2、进程在内存中有三部分组成:数据段、堆栈段和代码段。
代码段:就是存放程序代码的数据,如果有数个进程运行同一个一个程序,那么它们就可以使用同一个代码段(代码段是可以共享的);
堆栈段:存放的是子程序的返回地址、参数以及程序的局部变量,主要是保存进程的执行的环境,这里用到了栈先进后出的特性,可以看做具有记忆上一次执行的环境。
数据段:存放程序的全局变量 、常数    
//动态数据分配的数据空间
系统如果同时运行数个相同的程序,它们之间就不能使用同一个堆栈段和数据段,但是可以使用同一个代码段(代码段是可以共享的)

二、所要用到的函数

1 、fork()   功能:产生新的进程
1.1 依据返回值可以判断产生的是父进程还是子进程:
(1)== 0  子线程  ;(2)>0 父进程(此时返回值为子进程的进程号) ;(3) <  0 创建进程失败
1.2 父进程的进程号要比子进程的进程号小,因为父进程要比子线程早产生
1.3 进程的三个组成部分中代码段是父子进程共享的(同一个程序中),系统会复制数据段和堆栈段给子进程,父子进程会独立运行,互不影响。
1.4  fork函数执行一次,产生一个新进程,复制数据段、堆栈段,但是如果一个大程序在运行的时候,fork的时候复制数据段和堆栈段会开销很大。系统的解决的方法:一般CPU都是以页为单位分配空间的,无论是数据段还是堆栈段都是由很多页组成的,当实际执行fork的时候,物理空间上,两个进程的数据段和堆栈段还是共享的,逻辑上是分开的,只有当一个进程写某个数据的时候,这时两个进程之间的数据才有了区别,系统会将有区别的页从物理上 分开,而其他的不动,从而使系统在空间上的开销达到最小。(也就是说只有当有进程间的堆栈段和数据段是有区别的时候才会将二者分开,否则在物理空间上,二者依然是共享的)
   1.5 程序示例:
2、  getpid() 获得当前进程的进程ID
3、  getppid()  获得当前进程的父进程的进程ID
      4、exec类函数
在linux环境下,一个进程启动一个程序的执行可以使用exec类的函数来完成,这个exec类的函数包括:
(1)    int execv (const char *filename, char *const argv[])
(2)    int execl (const char *filename, const char *arg0, . . . )
(3)int execve (const char *filename, char *const argv[], char *const env[])
(4)int execle (const char *filename, const char *arg0, char const env[], . . . )
(5)int execvp (const char *filename, char *const argv[])
(6)int execlp (const char *filename, const char *arg0, . . . )
      一个进程一旦调用了exec类的函数,它本身就死了,它的代码段会被替换成新的程序代码,并且废弃原有的数据段和堆栈段,重新分配新的数据段和堆栈段,唯一留下的就是进程号,对于系统而言,还是同一个进程,不过这个进程已经是另一个程序了。如果一个程序想启动另一个程序的执行但是继续运行自己的话,需要结合fork函数和exec函数一块使用。
5    wait函数保证父进程运行完后等待子进程退出才退出,否则父进程结束了,子进程还在运行。
三、进程间通信
 linux系统中实现进程间通信的方式中常用的有:
(1)管道(2) 消息队列(3) 共享内存(4) 信号量 (5)套接口等。
3.1  管道
    管道是进程间通信的最古老的方式,分两种:
(1)无名管道(父进程和子进程间通信使用)。
(2)有名管道(同一机器上的任意两个进程间的通信使用)
3.1.1  无名管道
           无名管道由函数pipe()来创建   int pipe(int filedis[2]) 参数filedis返回两个文件的描述符号:filedis[0]为读而打开(只用来从里面读数据,不可写) ;filedis[1]为写而打开(只用来向里面写数据,不可读)。 filedis[1]的输出是filedis[0]的输入。
3.1.2  有名管道(有名管道就是有名字的管道):
linux系统下的有名管道由两方式创建:命令行方式mknod和函数mkfifo
方式一: mkfifo("myfifo","rw")
方式二: mknod  myfifo  p(使用file  myfifo可以看出它是一个命名管道)
上述两种方式都在当前目录下生成了一个名为fifo的有名管道。生成了有名管道后就
可以使用一般的文件io函数如open、 close、 read和writre对其进行操作了
        int mkfifo (const char filename, mode t mode)   sys/stat.h
    3.2  共享内存
      共享内存是运行在同一机器上的进程间的通信最快的方式,因为数据直接存在内存不需要在不同的进程间进行复制,通常由一个进程创建一个共享内存区,其余进程对这块内存进行读写。
      3.2.1  得到共享内存有两种方式:(1)映射/dev/mem设备(2)映射内存映像文件
        映射/dev/mem不给系统带来额外的开销,但是在实际中应用不常用,因为它控制存取的是实际的物理内存,在linux系统下,只有通过限制linux系统存取的内存才可以做到
       通常常用的方式是使用shmXXX函数族来实现共享内存进行存储
    3.2.2  所要用到的函数
int shmget(key_t key,int size,int flag)
 获得一个共享存储标识符,也就是请求分配size大小的内存用作共享内存  key_t关键字用来存储引用标识符,是个长整型数据,在头文件sys/types.h中定义。
上述函数执行完毕,共享内存就创建完毕了。
其余进程使用 shmat()函数就可以连接到自身的地址空间中了
    void
shmat(int shmid,void
addr,int flag)
   shmid为shmget函数返回的共享存储标识符
    addr和flag决定了以什么方式来确定连接地址
    函数的返回值就是该进程数据段所连接的实际地址,也就是共享内存的地址,进程可以对其进行读写操作
    使用共享存储来实现进程间的通信的注意点是对数据存取的同步,必须确保一个进程去读取数据时,它所想要的数据已经写好了,通常信号量可以被用来实现对共享存储数据存取的同步
3.3 套接字
 套接字是实现linux操作系统和其他操作系统之间的进程间通信的方式之一,www ftp telnet等服务都是基于套接字的
     除了适用于异地的计算机进程间通信外,套接字同样适用于本地同一计算机内部的进程间通信。

转载于:https://my.oschina.net/hnxymjj/blog/358777

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值