C总结

文件IO和进程线程


一、IO


文件IO: 如何通过代码操作文件,创建 删除 修改
进程线程: 多任务–多个进程同时工作,完成同一个任务

原理: 文件放在硬盘—硬件, 有系统管理

IO分为两个:

1.标准IO 标准C库提供的 通用的, 只针对普通文件
2.文件IO linux特有的 特有的 指针linux所有文件

linux除了支持普通文件外,还支持很多特有的文件,因为linux把一切都看做了文件.

标准IO:


操作: 创建 删除 打开fopen 关闭fclose 读fread和写fwrite 其他操作
读: 将硬件文件 读取到 内存中. 修改
写: 将内存数据写入到物理文件中.

函数:

1.fopen : file open
		 FILE * fopen(文件路径,指定读写权限)
		 
		 FILE *fp=fopen(argv[1],"r");	

2.fclose
		fclose(fp);
		
3.fread		
		int ret1 = fread(buf,1,sizeof(buf),fp);

4.fwrite
		int ret2 = fwrite(buf,1, ret1 ,fp);

5.  fgetc fputc  fgets ,他们是基于 fwrite fread实现的
		char fgetc(FILE *fp);        从文件中读取一个字符出来
		int fputc(char ch,FILE *fp)  向文件中写入一个字符
		
		fgets: 实现从文件中读取 一行数据.
		char *fgets(char *buf,int bufsize, FILE *fp  )

6、fopen之后,位置指针指向文件头部,fread /fwrite 会自动调整 位置指针.
		ftell()		----获取文件 当前位置指针的 位置(相对于文件头部)
		fseek()		---改变文件位置
7、errno --错误
		FILE *fopen(char *path,char *mode);
		可能出错,比如 文件不存在,比如 权限不满足 ......
		当你fopen失败的时候,你可能想知道 错误的具体原因,编译器帮你添加的.
	
		linux系统引入了一个 全局的整形变量errno
			当系统函数失败的时候,系统函数会把失败原因存放在errno中.使用见代码
	
	用法:
	例如:读入错误判断
		int ret = fread(buf,1,sizeof(buf),fp);
		if(ret<0){
			perror("fread err");
			return -11;
		}

文件IO:


删除文件 unlink, 独立于标准IO和文件IO
int unlink(char *path)

创建目录,删除目录,查看目录内容

1、查看目录内容:  direction     
	打开目录 opendir
		xx = opendir("目录路径")
2、读取目录内容 readdir
	{1.c,2.c subdir} = readdir(xx)
3、关闭目录 closedir
    closedir(xx)

目录,文件,目录项:
    /home/lsf/dir/1.c 
    / ,home,lsf,dir ---目录
    1.c    ------------文件

    /,home,lsf,dir,1.c---目录项: 是目录和文件的统称

    路径都是有目录项构成的

所用函数总结:

fopen   fclose  fread  fwrite     fseek   ftell    fgets   stdin  stdout stderr 
open    close   read   write      lseek                      0       1      2

二、进程与线程


1、进程


多任务: --------- 好处, 同时处理多个任务

  • 不相关的程序 多任务

  • 相关程序的 多任务进程 任务 程序

程序 a.out — 文件,静态
进程: 运行的程序 -动态: 1.程序在执行 2.动态访问资源(malloc open close )
当你在终端输入命令(程序)的时候,终端会把程序拷贝到内存中去.
然后执行内存的程序-----成为进程
任务: 进程就是为了完成某个任务

查看所有进程: 命令 : ps -aux

系统有上百个进程,如何进行区分 -------> 给每个进程分配一个id, 称为 pid: process id 进程号

linux系统中,所有的进程都有父子关系,这一切的源头是 一个pid=1进程,一般称为init进程

任何进程都是有他的父进程创建的,源头是 pid=1 init进程

父进程号: ppid parent pid 查看父进程------> ps -auxf

###如何产生子进程 ------> int fork (void)

main()
		{
			.....
			fork();
			....
			while(1){
				printf("run\n");
				sleep(1);
			}
		}
img

为什么要生产 子进程:

  • 完成新的任务

  • 多任务原理,CPU快速乱转执行进程

原理:
进程不可能无端产生
像是克隆clone:
产生了两个一模一样的个人, 独立两份空间,改变一个没有改变另一个

进程终结:

main()
{
while(n--){

}
}
exit(0);		编译器会自动帮你添加一行. 
exit:结束进程,并释放进程所占有的资源( 1.malloc    2.打开的文件 .... )
1.退出main函数		本质上还是调用了exit
2.exit()		进程主动调用exit函数结束自己,不需要退出main函数
#include <stdlib.h>
void exit(int status);   

	status这个值,传给父进程的,父进程会获取这个值,并进行响应的处理
	exit之后,进程还有一点点残余留在内存中,   僵尸进程
	如何彻底释放/收尸:  父进程来收尸
	如果父进程先死,则有爷爷来收尸.......最终 归到 pid=1进程  
	status,我们只用了 低8bit.所以要进行处理-->  stu= (status&0xFF00)>8
	
	3._exit()       进程调用它也可以结束.
		#include <unistd.h>
         void _exit(int status);
         
		他们都会结束当前进程,并释放进程的资源, 并传递参数给父进程
		exit:    它 会   清理标准io中的    文件缓存.  
		_exit:   它 不会 清理标准io中的  文件缓存.

收尸:

​ pid_t wait(int *stat) 阻塞等待…

exec 家族:

​ 我们创建子进程,大部分时候是为了执行新的程序. 而不是执行某个程序的分支.
​ execl execv execvp execlp…

img

进程间通信:

原理: 进程运行在os至上,os提供了很多共享资源,让他们进行通信

​ 最简单: 共享文件 共享内存 信号 …

=第一种 管道FIFO===

特点: FIFO 单向

管道本质上就是 在os中创建一个 临时文件,一个进程写入,一个进程读取

管道对文件进行了一点点改动:
1.文件是有大小的,一般只有4K/8K.
2.写入则存放数据,读取则删除数据;
3.如果满了,继续写—写进程阻塞等待空间
如果空,继续读—读进程阻塞等待

===============第二种 共享内存 share memery ==============

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zc43ZQgq-1661734599390)(G:%5C0001_huaqing_23800%5C%E5%B5%8C%E5%85%A5%E5%BC%8F_%E7%AC%94%E8%AE%B0%5C4.%E6%96%87%E4%BB%B6io%E5%92%8C%E8%BF%9B%E7%A8%8B%E7%BA%BF%E7%A8%8B%5C%E7%AC%94%E8%AE%B0%E5%9B%BE%E7%89%87%5C27.%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98%5C2.jpg)]

==第三种 信号 signal=

信号: 又称为 软件中断
进程执行循环任务,突然 系统给他一个信号,进程会暂停任务,转而去执行 信号处理函数,之后 返回继续执行任务.
优点:实时性很高

signal_handle()
{


}
main()
{
signal(2, signal_handle );
while(1){
打游戏
吃饭
睡觉
....

}
}
接收信号:
		进程执行循环任务,突然 系统给他一个信号,
		进程会暂停任务,转而去执行 信号处理函数,
		之后 返回继续执行任务.
	
	信号种类:	他们都是正数
		系统信号:
			SIGINT:   signal interrupt 打断信号, ctrl+c  
			SIGKILL:   signal kill       杀死进程信号,  kill -9  pid
			SIGSEGV:   signal segment   段错误信号
		用户信号:
			SIGUSR1  SIGUSR2

进程对收到的每一种信号,都有默认的处理方式		每种信号处理方式不一样一般默认都是 exit( )

进程如何指定 某种信号的处理方法  --->  signal(  信号,  处理方法       )

发送信号:
		1.kill 命令  :		kill -信号值  pid 
		2.kill 函数  :
			       #include <sys/types.h>
				   #include <signal.h>

				   int kill(pid_t pid, int sig);
							pid:接收信号的进程
							sig:信号值 
						返回值:  0-success   -1:errno

#####  定时器 #########
原理:  系统每隔一段时间,给进程发送一个信号SIGALRM,  alarm-- 
1. 进程指定收到SIGALRM信号后的动作     signal(SIGALRM,xxx_fun )
2.如何让系统 一直 间隔 给你发信号 int alarm( int sec )
	如果信号还没有到达时间,又来了一次alarm,会覆盖以前的请求
特殊: alarm(0) 立马删除所有的闹钟,当前不发生信号
##### 守护进程 ############
进程一直在干活.

如果一个进程在某个终端运行,当终端被关闭的时候,   
原理: 终端在死去之前,会给每一个子进程发送一个信号 SIGHUP,  handup-挂断
	1.当子进程收到信号之后,默认exit.    你可以替换进程默认的处理方式
	signal(SIGHUP, xxxxx);
	2.	nohup a.out    #######   使用nohup命令来执行程序,你的程序就不在遭受hup的伤害 
	一般nohup 要和& 一起使用,   &:让进程去后台执行
	效果  nohup ./xxxxx.out  &

注意事项: 信号处理函数,不要处理耗时的任务 包括延时 sleep(1)。

2、线程


进程可以实现多任务 但是:

  • 1.父进程拷贝自己生成子进程,浪费内存

  • 2.进程间通信 比较复杂和麻烦

轻量级的多任务… 线程thread

原理: 一个进程内部可有多个执行单元 同时执行 , 每一个执行单元称为 线程 这些线程,都在进程内部,共享进程的资源, 即不需要(进程间)通信了.

一个进程内部可以有很多线程,如何区分这些线程 —> 每个线程都有一个id, tid:thread id


int  aa,bb,cc,ee ,ff;		这些资源属于进程,大家都可以访问得到!!! 全局的变量是大家共享的
线程是共享(进程)资源的,但是每个线程都有自己独立空间
thread_fun( struct  tmsg *xxt )
{
xxt线程得到的参数
int xx,yy,zz;				这些东西属于该线程独有的

这是另外一个执行单元
while(1){

sleep(1);
}

}
int main(int argc,char **argv)
{
int mm,nn,oo;			这些东西属于主线程独有的

struct tmsg xxt;
//创建另外一个执行单元
tid = pthread_create(, 线程的执行函数, &xtt-给线程传递的参数  );
//得到该线程的tid

//执行单元1----
while(1){
//主进程以后都在这里面干活
sleep(1);
}

}

线程的退出:

  • 1.线程结束while(1)即可, return 参数

  • 2.线程调用pthread_exit(参数),两者效果一模一样

主线程如何控制子线程的死亡呢???

​ 建议用法,: 使用一个全局变量 来控制子线程

int global_run ;
子线程 while(global_run) {  
} 
main(){   
global_run=0/1; 
}

进程的优点:

  • 进程内线程共享资源的,包括全局变量 信号 还包括文件

  • 如果一个进程内部有很多线程,任何一个线程犯错 系统会给进程发段错误信号 整个进程结束…

  • 如果每个任务都是一个进程,某个死了 大家没事,还可以重启该进程…

线程的同步:

并发问题: 并行发生, 同时发生的

生活中: 同时访问同一个资源,造成的问题. 一般是不同时访问资源…

如何解决呢: 加锁 线程互斥锁: mutex—互斥–互斥访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8zwVHTQ4-1661734599391)(C:%5CUsers%5CWYH%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20220829005951826.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HeMj6LMc-1661734599392)(C:%5CUsers%5CWYH%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20220829010106303.png)]

用一个全局变量 来控制子线程

int global_run ;
子线程 while(global_run) {  
} 
main(){   
global_run=0/1; 
}

进程的优点:

  • 进程内线程共享资源的,包括全局变量 信号 还包括文件

  • 如果一个进程内部有很多线程,任何一个线程犯错 系统会给进程发段错误信号 整个进程结束…

  • 如果每个任务都是一个进程,某个死了 大家没事,还可以重启该进程…

线程的同步:

并发问题: 并行发生, 同时发生的

生活中: 同时访问同一个资源,造成的问题. 一般是不同时访问资源…

如何解决呢: 加锁 线程互斥锁: mutex—互斥–互斥访问

[外链图片转存中…(img-8zwVHTQ4-1661734599391)]

[外链图片转存中…(img-HeMj6LMc-1661734599392)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值