进程:进程是一个具有一定独立功能的程序的一次运行活动,同时也是资源分配的最小单元
程序是放到磁盘的可执行文件,进程是程序执行的实例
进程和程序的区别:进程是动态的,程序是静态的
进程是暂时的,程序是长久的
进程与程序的组成不同
进程与程序的对应关系:通过多次执行,一个程序可对应多个进程,通过调用关 系,一个进程包括多个程序
进程的创建,运行和撤销:每个进程都是由其父进程创建,进程可以创建子进程,子进程又可以创建子进程的子进程; 运行:对个进程可以同时存在,进程间可以通信;进程可以撤销,从而结束一个进程的运行
进程的三个状态:执行,就绪,等待
执行:程序正在占用cpu
就绪:进程具备一切条件,正在等待分配cpu的处理时间片
等待:进程不能使用cpu,若等待事件发生则可将其唤醒
Linux系统中的进程包含三个段:数据段,代码段和堆栈段
数据段:存放全局变量,常数以及动态数据分配的数据空间
代码段:存放的是程序代码的数据
堆栈段:存放子程序的返回地址,子程序的参数以及程序中的局部变量
如何创建一个进程
:
开机时
,
内核创建一个进程
: init,
内核不提供直接创建新进程的系统调用
.
所有的进程都由
init
进程通过
fork
机制创建
.
新的进程通过老的进程复制自身得到
.
这就是
fork,fork
是系统调用
.
可以当成一个函数使用
.
在进程
fork
时
,linux
会在内存中开辟一个新的内存空间给新的进程
,
并将老的进程空间的内容复制到新的空间
,
然后两个进程一起运行
.
进程标识
:
OS
会为每个进程分配一个唯一的整数
ID,
称之为进程标识号
(PID),
进程标识号为唯一的非负整数
. 0
表示调度进程
,
常称之为交换进程
.
该进程不执行任何磁盘上的文件
.
进程
ID 1
通常是
init
进程
,
该进程在系统自举时有系统调用
,
通产用于系统相关的初始化操作
,
该进程不会终止
,
是一个普通用户进程
,
但是以超级用户特权的身份运行
,
是所有的孤儿进程的父进程
.
进程除了自身
ID(PID)
外
,
还有父进程
ID(PPID),
所有进程的祖先进程是同一个进程
,
即
init
进程
.
#include<sys/types.h>
#include <unistd.h>
pit_t getpid(void);
pit_t getppid(void);
真实用户
ID
真实组
ID
有效用户
ID
有效组
ID
uid_t getuid(void);
uid_t geteuid(void);
linux
进程间同步互斥和死锁
一、
并发和竞争
并发指的是:多个执行单元同时并行被执行,而并发执行的单元由于对共享资源的访问,容易造成竞争态。
解决竞争的途径:保证对共享资源的互斥访问。所谓互斥访问就是指一个执行单元在使用共享资源的时候,其他的执行单元被禁止访问。
查看进程:
ps [
选项
]
-e:
显示所有的进程、环境变量
-f
:全格式
-h
:不显示标题
-l
:长格式
-w
:宽格式
a
:显示终端上的所有用户进程
r
:只显示正在运行的进程
x
:显示没有控制终端的进程
(后台进程)
pids
:
ps –f1,3,5
-o:
u:
按照用户名和启动时间顺序显示进程
j
:用任务格式显示进程
ww
:避免详细参数被截断
常用组合:
aux
或
lax f
D
:
R
:
S
:
T
:
W
:
X
:
Z
:
<: N : s: +:
kill
终止进程:
kill –STOP [pid] SIGSTOP
kill –CONT [pid] SIGCONT
kill –KILL [pid]
kill –l
kill -9 []
kill -15 []
top
ps
和
grep
组合
进程的创建和在子进程中运行别的程序
#include <unistd.h>
pid_t fork(void) 【pid_t 就是int】
返回值:小于0 错误 0 子进程 大于0 父进程
子进程的数据空间、堆栈空间都会从父进程得到一个拷贝,而不是共享。在子进程中对count进行加1的操作,并没有影响到父进程中的count值,父进程中的count值仍然为0
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void)
返回值:同fork
功能:创建子进程
fork 与vfork的区别
fork:子进程拷贝父进程的数据段
vfork:子进程与父进程共享数据段
fork:父、子进程的执行次序不确定
vfork:子进程先运行,父进程后运行
#include<unistd.h>
exec函数族
exec
用被执行的程序替换调用它的程序。
区别:
fork创建一个新的进程,产生一个新的PID。
exec启动一个新程序,替换原有的进程,因此进程的PID不会改变
int execl(const char * path,const char * arg1, ....)
参数:
path:被执行程序名(
含完整路径)。
arg1 – argn: 被执行程序所需的命令行参数,含程序名。
以空指针(NULL)结束。
#include<unistd.h>
int execv (const char * path, char * const argv[ ])
参数:
path:被执行程序名(含完整路径)。
argv[]: 被执行程序所需的命令行参数数组。
以空指针(NULL)结束。
其余exec函数省略,此两种最为常用
#include <stdlib.h>
int system( const char* string )
功能:
调用fork产生子进程,由子进程来调用/bin/sh -c string来执行参数string所代表的命令
僵尸进程的危害
:
一个进程调用
exit
退出时
,
并没有真正的被销毁
,
而是留下了一个称为僵尸进程的数据结构
.(
进程
ID,
退出状态
,
运行时间等
)
系统可使用进程号有限
,
如果大量产生僵尸进程将会因为没有可用进程号而导致系统不能产生新的进程
,
此即为僵尸进程的危害
.
僵尸进程的避免
:
1、
父进程通过
wait/waitpid
等函数等待子进程结束,这会导致父进程挂起
2、
如果父进程很忙,可以通过
signal
函数为
SIGCHLD
安装
handler
。
3、
如果父进程不关心子进程什么时候结束,可以使用
signal
(
SIGCHLD
,
SIG_IGN
)
通知内核,自己对子进程的结束不敢兴趣,有内核回收子进程。
#include <sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid,int * status,int options);
pid < -1 进程组
pid = -1 任意进程
pid = 0 当前进程组
pid > 0 指定进程
options
取值:
0 (阻塞)
或者
WNOHANF(非阻塞)
或
WUNTRACED
wait
和
waitpid
的区别:
1、
wait
使用阻塞状态,而
waitpid
可以有非阻塞状态的选择
2、
waitpid
并不是等待其调用之后第一个终止的进程,有若干选项可以控制它所等待的进程,
wait
只能等待调用之后第一个终止的进程
3、
wait
唯一的出错是调用进程没有子进程
waitpid
若指定的进程或进程组不存在或者
pid
指定的进程不是调用进程的子进程都可能出错。
4、
waitpid
提供了
wait
没有的三个功能:
指定特定的进程
提供非阻塞状态
waitpid
支持作业控制
5、
wait
(
&status
)功能相当于
waitpid(-1,&status,0)