函数补充:
1、【sprintf】:
形式:【int sprintf(char *str, const char *format, ...);】
sprintf(数组,“%s %s”,字符串1,字符串2);
可以将字符串一和字符串2拼接在一起,装在数组中;
eg:(1)打开指定目录下的所有文件(递归法)
2、【fprintf】:
int fprintf(FILE *stream, const char *format, ...);
【FILE *stream】;文件流指针;
【const char *format, ...】需要输入文件的内容;
一般配合fflush(fp);函数一起使用,用于刷新写入的内容;
eg:(2)设计一个程序,动态生成两个进程,分别向相同的文件中 写入不同的数据,要表明是两个进程同时写入的数据。 父进程1123 186 16:02:10,, 子进程1124 188 16:02:15
#include <dirent.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
int times() {
time_t tm;
tm = time(NULL);
return tm;
}
int wenjianzonghe() {
DIR *dir = opendir("/proc");
if (NULL == dir) {
perror("opendir");
return 1;
}
int i = 0;
int t = 0;
while (1) {
struct dirent *info = readdir(dir);
if (NULL == info) {
break;
}
if (info->d_name[0] >= 48 && info->d_name[0] <= 57) {
++i;
}
}
closedir(dir);
return i;
}
int main(int argc, char **argv) {
FILE *fp = fopen("1.txt", "w");
if (NULL == fp) {
perror("fopen");
return 1;
}
pid_t ret = fork();
if (ret > 0) {
while (1) {
int num = wenjianzonghe();
long int t = times();
struct tm *tminfo = localtime(&t);
fprintf(fp,"父进程 %d %d %d-%d-%d %d:%d:%d\n", getpid(), num,
tminfo->tm_year + 1900, tminfo->tm_mon + 1, tminfo->tm_mday,
tminfo->tm_hour, tminfo->tm_min, tminfo->tm_sec);
fflush(fp);
sleep(3);
}
}
if (ret == 0) {
while (1) {
int num = wenjianzonghe();
long int t = times();
struct tm *tminfo = localtime(&t);
fprintf(fp,"子进程 %d %d %d-%d-%d %d:%d:%d\n", getpid(), num,
tminfo->tm_year + 1900, tminfo->tm_mon + 1, tminfo->tm_mday,
tminfo->tm_hour, tminfo->tm_min, tminfo->tm_sec);
fflush(fp);
sleep(6);
}
}
else
{
perror("fork");
return 1;
}
fclose(fp);
return 0;
}
3、man -k //模糊搜索
【man -k 输入函数的前面部分】
二、进程
1、进程的定义
定义:进程是一个程序执行的过程中,会去分配内存资源和CPU的调度;
作用:让操作系统并发执行,希望在短的时间内,多个任务同时进行
pcb 是一个结构体,process control block print circuit board
vim -t
task_structPID,进程标识符
当前工作路径 chdir //了解
umask 0002 //了解
进程打开的文件列表 文件IO中有提到
信号相关设置 处理异步io,
用户id,组id
进程资源的上限
ulimit -a,显示资源上限。
2、进程和程序的区别
程序:静态
存储在硬盘中代码,数据的集合;进程:动态
程序执行的过程,包括进程的创建、调度、消亡;.c ----> a.out-----> process(pid)(程序运行起来便有进程)
1)程序是永存,进程是暂时的
2)进程有程序状态的变化,程序没有
3)进程可以并发,程序无并发
4)进程与进程会存在竞争计算机的资源
5)一个程序可以运行多次,变成多个进程
一个进程可以运行一个或多个程序
3、内存的分布
0-3G,是进程的空间,3G-4G是内核的空间,虚拟地址
虚拟地址 * 物理内存和虚拟内存的地址 映射表 1page=4kMAP /share共享库
Stack栈 // 8Mb
heap堆 //动态内存空间,由程序员申请可以使用的空间;
data数据 //存放全局变量和静态变量;
code代码段,//只读;
MMU:虚拟空间
1、透明;
2、隔离;
3、权限
映射表
(1)映射表将虚拟内存的地址转换为物理内存的地址;
(2)映射表通常由页表(Page Table)组成,它记录了虚拟地址到物理地址的映射关
系;
(3)一个页面大小通常为4k(4036字节);
4、进程的分类
1、交互式进程
2、批处理进程 shell脚本 (批量执行一次命令)
3、 守护进程 (程序走起来不需要输入,eg:杀毒类软件、启动输入法)
5、进程的状态
3个状态,就绪→执行态→阻塞(等待,睡眠)基本操作系统
linux中的状态,运行态,睡眠态,僵尸,暂停态。
6、查询进程的相关命令【ps aux】
6.1查询进程的相关命令【ps aux】
【ps aux】
6.1.1 查看进程相关信息
1.就绪态、运行态 R
2.睡眠态、等待态
可唤醒等待态 S
不可唤醒等待态 D
3.停止态 T
4.僵尸态 Z
5.结束态1.ps aux 查看进程相关信息
|less 屏满等待
|grep 51283 51283为进程的PID,寻找该PID
2. pstree 查看进程树
pstree -p 查看进程树,显示PID
6.2查询进程的相关命令【top】
根据CPU占用率查看进程相关信息
6.3关闭进程的相关命令【kill】
kill -2 PID 15
发送信号+PID对应的进程,默认接收者关闭
其中【-2】代表发送几号信号(信号编号),可以用【kill - l】查看64中信号
当不输入信号编号时,默认为15号信号;
-2 委婉提醒关闭;
-9是强制关闭;
killall -9 进程名
发送信号 进程名对应的所有进程
killall a.out
7、 进程的调度,进程上下文切换
内核主要功能之一就是完成进程调度, 硬件,bios,io,文件系统,驱动调度算法,
other,idle
rr,fifo
宏观并行:在一个时间段多个任务和进程是同时进行的
微观串行:在一个时间点只能一条一条指令执行
实时操作系统:规定时间内完成
分时操作系统:尽量在规定时间内完成(如Linux、Windows等)
后台任务
1、先来先服务; 2、短任务优先 3、优先级,高优先级先行 4、时间片轮转
进程上下文切换:就是值指调度器要切换CPU给另一个进程的时候,要保存当前进
程的状态,然后加载打开一个新的进程这样的一个过程。
8、进程的作用
1、并发性:允许多个进程同时运行,提高了CPU利用率和系统响应速度;
2、稳定性:如果一个进程发生错误,通常不会影响到其他进程,这提高了系统的稳定
性;
三、进程相关函数
1、fork()
形式:
pid_t fork(void);
功能:通过该函数可以从当前进程中克隆一个同名新进程。
克隆的进程称为子进程,原有的进程称为 父进程。
子进程是父进程的完全拷贝。
子进程的执行过程是从fork函数之后执行。
该函数一次调用,会返回两次;
返回值:int 类型的数字。
在父进程中:成功 返回值是子进程的pid号 >0
失败 返回-1;
在子进程中:成功 返回值 0
失败 无
在调用之后注意:
①是父进程先运行还是子进程先运行,顺序不确定;
②变量不共享;
③子进程与父进程具有相同的代码逻辑。
④子进程的执行过程是从fork函数之后执行。
⑤子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同(子的id比父大)
⑥子进程与父进程谁先消亡是随机的,谁跑得快谁先消亡
eg:使用fork函数,观察父子进程运行状态,并且验证父子进程的变量不共享;
2、getpid()
形式:
pid_t getpid(void);
功能:
获得调用该函数进程的pid
返回值:
返回值为当前进程的pid号;
3、getppid()
形式:
pid_t getppid(void);
功能:
获得调用该函数父进程的pid
返回值:
返回值为当前进程父进程的pid号;
4、
四、写时复制
写时拷贝:为了提高效率,Linux采用写时拷贝技术,即只有在父或子进程修改数据时才真正复制。
优点:提高效率、创建子进程速度快、开的空间少、回收速度快。
五、进程的终止
(1)主动退出
1)main 中return
2)exit(), c库函数,会执行io库的清理工作,关闭所有 的流,以及所有打开的文件。已经清理函数(atexit)。
3)_exit,_Exit 会关闭所有的已经打开的文件,不执行清理函数。
4) 主线程退出
5)主线程调用pthread_exit
(2)异常终止
1)【abort()】:该函数禁止应用层调用,发生严重错误系统调用;
2)【signal kill pid】:有权限的发送信号(内存访问错误则发送信号结束)
3)最后一个线程被pthread_cancle
1、exit 库函数
退出状态,终止的进程会通知父进程,自己是如何终止的。如果是正常结束(终止),则由exit传入的参数。如果是异常终止,则有内核通知异常终止原因的状态。任何情况下,父进程都能使用wait,waitpid获得这个状态,以及资源的回收。
void exit(int status)
exit(1);
功能:
让进程退出,并刷新缓存区
参数:
status:进程退出的状态
返回值:
缺省
2._exit 系统调用
void _exit(int status);
功能:
让进程退出,不刷新缓存区
参数:
status:进程退出状态
返回值:
缺省