Linux进程编程

进程是操作系统中最基本、最重要的概念,可以说进程是操作系统结构的基础。操作系统上任何程序的执行都离不开进程。

1.进程的概念

传统的程序本是一组指令的集合,是一个静态实体,无法描述程序在内存中的执行情况,也就不能如实反映程序并发执行过程的特征,为了深刻描述程序动态执行过程的性质,人们就引入了“进程”的概念。 进程在系统中表现为一种数据结构,实现对正在运行的程序过程的抽象,其中进程由三个部分组成:

  • 进程控制块(PCB)–进程控制块是描述和控制进程运行的一个数据结构,主要包含进程标识符,进程控制和调度信息等,这些信息使程序成为一个能与其他进程并发运行的进程,操作系统是通过进程控制块来控制进程的运行。
  • 代码段–是存放程序代码的数据,假如系统中有多个进程运行相同的一个程序,则可以使用同一个代码段。

进程的主要特征:

  • 动态性–进程的实质是程序的一次执行过程,进程是动态产生,动态消亡。
  • 并发性–表现为可以和其他进程一起并发执行。
  • 独立性–进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的基本单位。
  • 异步性–由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的,不可预知的速度向前推进。

由于进程执行时的时间间断性,运行中的进程可能有三种基本状态:

  • 就绪状态–指进程已分配到处理器以外的所有必要资源,具备了可以执行的所有条件。
  • 执行状态--指进程占用处理器,进程的程序正在执行
  • 阻塞状态–指进程由于等待某种事件的发生而处于暂停执行的状态。

Linux调度器将进程分为三种不同类型,每种进程都有自己的特点和属性:

  • 交互进程--由一个Shell启动的进程,此类进程有大量的人机交互,既可以在前台进行,也可以在后台运行。
  • 批处理进程–这种进程不需要人机交互,运行于后台,需要大量的系统资源,是一个进程序列。
  • 监控进程–也称为守护进程,Linux启动时启动的进程,并在后台一直进行,等待请求处理任务。
2.进程的操作

在Linux系统中定义了一系列的进程操作函数,包括进程的创建、调度、终止等。

1. 进程的创建

一个进程创建了子进程,其中创建子进程的进程我们称为父进程,除了创建与被创建之外,父进程与子进程之间的关系也是管理与被管理的关系。
Linux系统启动时处于核心模式,此时只有一个进程:初始化进程(init进程),其进程号为1,Linux系统中的所有进程都是由init进程直接或间接创建的。
程序可以通过getpid()获得自身所运行的进程ID,也可以通过getppid()获取父进程的ID。创建进程时,通过函数fork()

2.进程的调度 sched.h

Linux系统内核中有一个进程控制表,进程控制表每一项都是一个task_struct结构,即代表了一个进程。Linux内虽然进程都是动态分配的,但还是需要考虑最大进程数。在系统中,默认的最大进程数是512,即表示系统中可同时容纳的进程个数为512个。
Linux管理进程的最好方法是使用命令来管理,主要涉及的命令有ps at top kill pstree nice renice等。

3. 进程的终止

子进程一旦被创建,就与其父进程一起被系统进行调度,子进程运行完毕后,并不立即释放所占有的所有进程控制表项,而是作为僵尸进程存在于系统中,直到父进程正常退出或调用wait()函数,子进程才彻底终止。

pid-t wait(int *status);
pdi_t waitpid(pid_t pid, int *status, int options);

options:
    WNOHANG--要求如果没有子进程退出就立即返回
    WUNTRACED--对已经停止但为报告状态的子进程
该调用也从等待中返回和报告状态,如果status不为空,调用将使status指向该信息。

调用了wait()函数的父进程会马上阻塞自己,由wait()函数自动分析是否当前进程的某一个子进程已经退出,如果找到了这样一个僵尸进程,wait()函数就会收集这个子进程的信息,将它彻底终止并返回子进程的结束状态,如果没有找到这样一个子进程,wait()函数就会一直阻塞在这里,直到找到一个变成僵尸进程的子进程出现为止,但如果父进程还未调用wait()函数就终止了,此时子进程就将被init进程接管,它将控制子进程退出后必须的清除工作。

3.进程间的通讯 systemV posix

在同一台计算机中的进程相互通信的方式主要有:管道(pipe)、信号(signal)、信号量(semaphore)、消息队列(message)、共享内存(shared memory),其中信号量、消息队列、共享内存被称为IPC机制。不同机器之间的进程通讯可以使用套接字技术。

1.管道

管道是IPC机制中的最老形式,是进程直接进行数据交换的通道,并且所有UNIX系统都提供了这种通信机制,管道分为普通管道和命名管道。它们都是通过内核缓冲区按照先进先出的方式进行数据传输,其普通管道的特点为:

  • 半双工
  • 只能在具有共同祖先的进程之间使用
  • 单独构成一种独立的文件系统
  • 没有名字
  • 管道的缓冲区是有限的
  • 管道的传送数据是无格式的
  • 写入管道的数据读完之后就从管道中消失

管道的创建和读写
无名管道

#include <unistd.h>
创建管道:int pipe(int pipefd[2]);
pipe[0]-->读数据
pipe[1]-->写数据

命名管道

创建管道:int mkfifo(const char *pathname, mode_t mode);

一般文件的I/O操作函数都可以用于管道。

close(fd);
int read(fd, buffer, len);
int write(fd, buffer, len);
2.信号 signal()

信号是的一种重要的进程方式,类似于中断机制,由某些错误条件而产生的事件,如果不指定,系统会调用默认操作来处理信号,大部分信号的默认操作将会终止进程。进程可以指定处理函数,由该函数处理,也可以忽略某个信号,对该信号不做任何处理,就像未发生过一样。

signal函数的原型
void (*signal(int signum, void (* handler) (int))) (int)

对于信号的操作,一般步骤为:安装信号,实现信号处理函数,发送信号,信号的生命周期从发送信号开始,到相应的处理函数执行完毕后结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值