库和进程
【1】静态库和动态库
库:本质上库是一种可执行代码的二进制形式,可以被操作系统载入内存执行,不同操作系统注意库不兼容
静态库:在程序编译时会被链接到目标代码中,因此体积较大,程序运行时不再需要静态库
动态库(共享库):在程序运行时才被载入,因此体积较小,程序运行时需要动态库
【2】静态库的制作
1.得到目标文件
gcc -c XXX.c -o XXX.o
2.生成静态库
ar crs libXXX.a XXX.o
3.编译运行
gcc main.c -o main -L. -lXXX
-L 指定库的路径
-l 指定库的名字
【3】动态库(共享库)的制作
1.得到目标文件
gcc -c -fPIC XXX.c -o XXX.o
2.生成共享库
gcc -shared XXX.o -o libXXX.so
3.编译运行
gcc main.c -o main -L. -lXXX
【4】动态库的加载方法
1.将库拷贝到/lib或/usr/lib下
注意权限问题
2.将库的路径添加到环境变量中
export LD_LIBRARY_PATH=/home/linux/IO_process/1902/day_3/share/
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
【5】进程的概念
进程就是一个程序的一次执行过程,它包括创建、执行、调度、消亡
进程是微观串行,宏观是并行
进程和程序有啥区别?
程序是静态的,它是一个保存在磁盘上的指令的有序集合,没有任何可执行的概念
进程是一个动态的,它是程序的一次执行过程,它包括创建、执行、调度、消亡
【6】task_struct 进程控制块(pcb)(管理进程)
1.进程标识pid
2.文件描述符表
3.进程的状态
4.pc程序计数器(存放程序下一条指令的地址)
【7】进程的类型
1.交互进程
该类型进程是shell控制和运行的
前台进程:目前我们一直用的 +代表前台运行
后台进程:在后台运行,只有输出,没有输入 没有+代表后台运行 ./a.out &
2.批处理进程
3.守护进程
该类型进程在后台运行,它一般在linux启动时开始执行,系统关闭才结束
【8】进程的状态
D uninterruptible sleep (usually IO)
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped, either by a job control signal or because it is
being traced
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by
its parent
For BSD formats and when the stat keyword is used, additional
characters may be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads
do)
+ is in the foreground process group
【9】进程相关的命令
1.查看进程的信息
ps aux
ps -ef
top
pstree
cd /proc
2.给进程发送信号的命令
kill -l
kill -信号 进程号
3.优先级相关的命令
NI [-20,19] 数越小,优先级越高
默认的优先级是0
nice -5 ./a.out 设置优先级为5
sudo nice --3 ./a.out 设置优先级为-3,优先级比较高时需要权限
sudo renice +5 16020 给pid为16020修改优先级为5
sudo renice -5 16020 给pid为16020修改优先级为-5
4.后台进程相关命令
bg 将挂起的进程在后台执行
fg 作业号 将后台运行的进程放到前台执行
jobs 查看后台进程
【10】创建进程
#include <unistd.h>
pid_t fork(void);
功能:创建进程
返回值:成功返回两个值,一个大于0的,是子进程的pid,此进程代表的是父进程
一个等于0,此进程代表的是子进程
失败 -1
【11】获得pid和ppid
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
功能:获得当前进程的pid
返回值:进程的pid
pid_t getppid(void);
功能:获得当前进程的父进程的pid
返回值:获得的pid号
【12】进程的退出
#include <stdlib.h>
void exit(int status);
功能:进程的退出并且刷新缓存区
参数:status 退出的状态
一般:0代表正常退出 1代表异常退出
#include <unistd.h>
void _exit(int status);
功能:进程的退出,但不刷新缓存区
参数:status 退出的状态
一般:0代表正常退出 1代表异常退出
【13】exec函数族
功能:在一个进程中,启动执行另外一个进程
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
功能:在一个进程中,启动执行另外一个进程
参数:path 要执行的可执行文件的路径
arg 可变参数
第一个参数必须和可执行文件名一致
最后一个参数必须是NULL
返回值:失败返回-1
int execlp(const char *file, const char *arg, ...);
功能:在一个进程中,启动执行另外一个进程
参数:file 要执行的可执行文件的文件名
arg 可变参数
第一个参数必须和可执行文件名一致
最后一个参数必须是NULL
返回值:失败返回-1
练习:父进程中用execl执行ls命令,子进程中用execlp执行ps命令
疑问(周末先自己解决):1.老师,我只能执行系统定义好的命令吗?
2.老师,我想执行下自己的代码?
【14】孤儿进程
父进程退出,儿子活着
【15】僵尸进程
儿子退出,父进程活着,但是没有回收儿子的资源
【16】如何避免僵尸进程
1.资源回收
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
功能:阻塞等待资源的回收
参数:status 保存进程退出的状态
如果传NULL,代表不关心进程的退出状态
返回值:成功返回进程号,失败返回-1