简述
io分为标准io和文件io,标准io是基于c库的,可以在多个场景下应用。文件io是包含标准io的,只可以应用在Linux系统之上。
函数
标准io函数 文件io函数
fopen open
fread read
fwrite write
fclose close
fseek lseek
ftell
标准io里还有几个特殊的函数
fgetc(从文件中读取一个字符到内存中)
fputc(将内存中的一个字符写到文件中)
fgets(从文件中获取一行数据到内存中)
函数的具体用法可以在Linux终端使用man命令查看。
终端(terminal)的原理
区别:
stdout文件:该文件中没有缓冲,写入的内容立即输出
stderr文件:文件内部里有一个缓冲区,写入的内容不会立即输出(1.遇到了\n 2.缓冲区满了)
任务 进程 程序
程序:是一个存储在硬盘的一个静态文件
进程:是一个正在运行的程序,是动态的
任务:创建进程就是完成任务,一般把进程也称为任务
可以通过 ps - aux命令来查看系统的进程
每个进程系统都会分配一个唯一的id来区别,pid(process id),可以通过getpid()函数来获取进程号
每个进程都会有一个父进程号,ppid(parent pid),可以通过getppid()函数来获取父进程号
可以通过fork()函数来创建自己的子进程
进程的退出:
1.进程退出main函数,一切都结束
2.进程可以调用exit()函数来结束自己,exit函数会结束自己,释放资源,同时向父进程号传递一个数值来表达自己的退出原因。
3.进程可以调用_exit函数来结束自己
exit() 结束时会清理文件缓存
_exit() 结束时不会清理文件缓存
僵尸进程:
进程可以调用exit函数来结束自己,释放资源,同时进程会保留一点垃圾在内存中,这就是僵尸进程。留下来的垃圾会由他的父进程来进行收尸,如果父进程先死的话系统会将收尸的任务交给他的爷爷进程,依次推到init进程(进程号=1)
exec函数族:
将进程的内容进行覆盖。
进程间的通信:
1.管道pipe(就是一个特殊的共享文件)
特点:单向通信,FIFO结构,如果要实现双向通信的话可以创建两个管道文件。
分为两类:无名管道:被淘汰(只能在父子进程之间进行通信)
有名管道:至今还在使用
特征:1.文件存在内存中,不存在硬盘里(速度快,断电了不存在)
2.文件有固定的大小(4kb)
3.数据被读走后就会被删除,读取的时候发现没有数据会一直等待数据的写入
写入的时候发现写满了,会等数据被读取后再写
2.共享内存
优点:双向通信,不用数据的拷贝(管道需要拷贝两次)
缺点:进程同时访问会造成数据的不正确(可以给内存设置标志位来判断哪个进程来进行)
3.信号signal
Linux进程在收到信号的时候,会中断当前任务的执行,先去执行信号函数的内容,再回来执行剩下的任务。
可以在终端里输入kill -l来查看各种信号
2.SIGINT,就是我们在终端使用了ctrl+c,将进程杀死
3.SIGSEGV(段错误),当进程访问了非法的地址,被系统发现以后,会让程序进行自杀
9.SIGKILL,杀死某个进程 (kill -9 pid)
进程可以修改某个信号的执行内容,当进程收到信号时,可以执行其他的操作。
SIGKILL SIGTSTP函数不会被修改。
信号的几个应用:1.给子进程收尸
2.应用定时器(SIGALRM)
3.守护进程(程序要一直执行)
线程:
线程:通信简单 占用空间小(共享空间) 独立性差,安全性低
进程:通信麻烦 占用空间大(开辟新空间) 独立性强,安全性高
并发:
多个线程同时访问一个资源造成数据的混乱,出错
我们可以通过给线程上锁来解决并发问题
互斥锁:
首先初始化一把锁:
pthread_mutex_t mlock = PTHREAD_MUTEX_INITIALIZER;
访问之前先加锁:
pthread_mutex_lock( &mlock );
访问之后解锁:
pthread_mutex_unlock( &mlock );
原理:线程访问时,发现锁是开着的,就会去加锁,然后运行自己的程序,再把锁解开
当发现锁是锁着的时候,就会一直等待,锁被打开的时候在重复上述的步骤。
库
分为动态库以及静态库
区别:
动态库:每个程序共享一份(占用空间小) 移植性差 独立性差,依赖性强
静态库:每个程序都有一份(占用空间大) 移植性好 独立性高,依赖性差
制作动态库:
先将库文件的每个.c文件都编译为.o文件(-fPIC,将代码编译为 #地址位置无关#的程序)
gcc media.c -fPIC -c -o media.o
gcc ui.c -fPIC -c -o ui.o
再将.o文件进行打包,生成一个动态库 libxx.so
gcc -shared *.o -o libxx.so
再通过gcc命令(要先将动态库文件放在Linux系统的指定目录下,一般我们放在usr/lib文件下)
gcc main.c -L 库文件路径 -l 指定库的名字 -o xx.out