2024Spring,Dian,Project-oriented
Day 1 学会科学上网... 注册github,创建git仓库并学习本地提交文件常用指令,链接本地仓库与github; 安装linux虚拟机(RedHat,linux9.3),配置Linux系统; (被困很久的)将本机clash代理用在虚拟机的网络代理上,花费很长时间的主要原因是对linux虚拟机网络配置原理不熟悉,网上看到的各种方法细节上有所差别,最后看到几个思路相似的方法应用验证后解决了问题; 补充:最后发现其实linux虚拟机并不需要clash联网,使用ssh将主机和虚拟机ip地址连接起来,就可以在主机的vscode上写代码了; Day2-Day3 开始配置linuxC语言环境; 在需要命令行下载c语言环境配置需要的库文件以及sudo ... 各种apt-get时报错网络问题,检查发现虚拟机浏览器可以上网,但终端无法上网; 尝试了很多方法都没有解决,并发现RedHat需要register系统获得权限,但是依然各种方法尝试登陆账号都没登上... 最终换了一个Ubuntu的.iso文件,重装虚拟机、修改网络配置后解决问题;(感觉到Ubuntu系统比RedHat要容易操作一点点...指的是对于没接触过linux系统的新手来说...) 学习命令行参数解析,编写test函数,-c打印完成;(-h文档留在最后填坑) Day 4 安装ffmpeg,下载相关库文件; 写初始化测试代码尝试使用video_decoder库中的decoder_init()函数,报错segmentation fault(core dumped),搜索方法尝试解决; (周五满课所以本日写代码时间较少...) Day 5 继续尝试解决segmentation fault问题:根据搜索结果学习修改ulimit -c大小,之后在运行报错产生core文件后,使用gdb查看core文件,定位报错位置; 学习使用gdb (filename)进行debug(虽然没de出来...); 在复现网上的各种方法后大致确定是有关库的问题,但还是没有解决; 在招新群里求助,最终确认原因可能是ffmpeg版本不兼容,将videodecoder.h和.c源码重新编译后再尝试链接就可以初始化以及获得视频帧信息了; 尝试编写灰度图打印代码; Day 6 尝试使用videodecoder库中的函数; 继续学习RGB图像、灰度图像相关内容,试图实现灰度图打印,但(可能)由于原图帧数据太大,打印了一小部分就报错segmentation fault,故先尝试实现池化; 学习池化内容,编写函数实现灰度数据(二维矩阵)的average pooling 和 max pooling,实现对图像的灰度(字符)打印; 学习ASCII码转义字符的颜色表示,打印彩色字符(的尝试); 由于rgb彩色图像打印需要的数据和以上灰度数据池化的原始数据不同(需要保留r、g、b),所以继续编写彩色打印的color average pooling函数和color max pooling函数; 基本实现打印,但存在数据错位问题(考虑可能是访问数据位置有问题,但当天未能成功debug...) Day 7 学习Linux下C语言多线程基础知识; 修改彩色打印错位问题(访问原始数据位置出错)和打印形式问题(将彩色方块字符错用为彩色字符); 完善彩色打印的max pooling函数; 实现帧的可调节; 基本创建多线程、队列实现缓冲区的思路,大致完成代码框架; Day 8 整理现有的可以跑的代码,补充readme文档; 补充完整命令行传参数部分(之前初次尝试时使用getopt()函数,但该函数只能支持短参数如-c,所以学习getopt_long()函数,使命令行支持两种形式的选项参数); 完成level 2-2跳帧; 继续写多线程代码; 完成2-2,level3,上传git;
———————————————————————————————————————————————————————————————————————————— level 0 (0-2) 1.int getopt(int argc, char * const argv[], const char *optstring) char *optstring = "ab:c::" 单个字符a 表示选项a没有参数;单字符加冒号b: 表示选项b有且必须加参数;单字符加2冒号c:: 表示选项c可以有,也可以无
命令行选项解析函数(C语言):getopt()和getopt_long() - 肖邦linux - 博客园 https://www.cnblogs.com/liwei0526vip/p/4873111.html www.cnblogs.com (0-3) 2.linux 下的 .a(静态库) 文件 .so(动态库) 文件 静态链接的可执行文件要比动态链接的可执行文件要大得多,因为它将需要用到的代码从二进制文件中“拷贝”了一份,而动态库仅仅是复制了一些重定位和符号表信息;
浅谈静态库和动态库 - 知乎 https://zhuanlan.zhihu.com/p/71372182 zhuanlan.zhihu.com 注:编译时链接库;也需要#include库; 3.完善命令行调用; ·使用getopt_long()函数,可以支持--help(例)和--h两种类型的命令行参数; ·特殊情况,调整命令行输入修改池化参数window,step时需要获取同意选项下的两个参数,采用: 当处理到–command的时候 argv[optind-1] = 11; argv[optind ] = 22; argv[optind+1] = 33; 最后再将获得的char类型参数atoi,即可获得两个int 类型的池化参数;
level 1 (1-1) 1.关于库函数 get_fps()"帧率": 帧率:frames per second 2.decoder_init时参数加入视频地址后运行报错Segmentation fault (core dumped) 尝试使用gdb ./~ core查看崩溃原因定位;查看log文件; /var/log/apport.log查看崩溃记录,查看core文件报错引导; 加入./libvideodecoder.a 后报错undefined reference to symbol 'avcodec_open2@@LIBAVCODEC_60' 3.rgb转灰度算法: 采用0.299 * r + 0.587 * g + 0.114 * b (1-2)resize函数 1.在c工程中,源文件中要包含自己的头文件; //2.由于RGB图像对应R、G、B三个通道的数据,故而不能直接池化,需要先进行卷积,再用之后得到的数据进行池化; 2.对RGB图像,采取: // 遍历窗口内的像素,通过比较窗口内元素的灰度值 //找到灰度值最大的像素,作为当前窗口内最具代表性的颜色值,保存索引 //根据其打印彩色字符
level 2
(2-1)
1.多线程编程;进程和线程
·一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间,不包括栈)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。
·条件竞争的解决:pthread_join()函数、互斥锁机制和信号量机制:
(n=1:互斥锁,eg.生产者消费者模型)通过访问时对共享资源加锁的方法,防止多个线程同时访问共享资源。锁有两种状态:未上锁和已上锁。在访问共享资源时,进行上锁,在访问结束后,进行解锁。若在访问时,共享资源已被其它线程锁住了,则进入堵塞状态等待该线程释放锁再继续下一步的执行。这种锁我们称为互斥锁。
(n>=1:信号量机制)
·代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。
tips:
①被释放的内存空间仅仅是系统空间,你必须手动清除程序分配的空间,比如 malloc() 分配的空间。
②一个线程只能被一个线程所连接。
③被连接的线程必须是非分离的,否则连接会出错。
所以可以看出pthread_join()有两种作用:
用于等待其他线程结束:当调用 pthread_join() 时,当前线程会处于阻塞状态,直到被调用的线程结束后,当前线程才会重新开始执行。
对线程的资源进行回收:如果一个线程是非分离的(默认情况下创建的线程都是非分离)并且没有对该线程使用 pthread_join() 的话,该线程结束后并不会释放其内存空间,这会导致该线程变成了“僵尸线程”。
2.buffer
缓冲区的作用
在计算机里应用程序调用一个系统调用从用户态进去内核态再将结果回到用户态开销较大。如果我们调用printf函数,每次输出一个字符都要从用户态切换到内核态,那么连续输出多个字符开销成本将会非常大,这个时候缓存就起到非常大的作用了,输出的字符串先在应用程序里缓存起来,缓存到一定数量后再调用系统调用一次性将缓存数据输出到标准输出。由于只调用了一次系统调用,比连续调用多个系统调用性能高上不少。
·buffer中数据的存取
3.缓冲模式:行缓冲、完全缓冲、无缓冲