网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
printf("%d: received pong\n", pid);
}
exit(0);
}
}
}
3. 在Makefile文件里面UPROGS 添加 $U/\_pingpong\;
UPROGS=
$U/_cat
$U/_echo
$U/_forktest
$U/_grep
…
$U/_sleep\
$U/_pingpong\ //添加进Makefile
4. 直接重新编译***make qemu***,或者用测试脚本测试,我这里就放一下用脚本测试的方法和结果;
jimmy@ubuntu:~/xv6-labs-2020$ ./grade-lab-util pingpong
make: ‘kernel/kernel’ is up to date.
== Test pingpong == pingpong: OK (1.4s)
### primes函数实现
1.写一个素数筛选的程序,需要用到多进程和管道,这道题理解主要靠下面的图。

大概流程就是,输入2-11,然后发现2是素数,然后将能被2整除的素数全部筛掉。然后发现3是素数,在第二个阶段中将能被3整除的筛掉。
**(牢记:每个进程的第一个数必定是素数)**
2.根据上面的描述,需要写一个递归函数,这个函数要做的就是让父进程判断当前所有的数字中有没有能被第一个数整除的,如果不能整除,就用子进程把它送到下一次递归。然后利用这种链式结构,就像上面的图一样,完成筛选。
#include “kernel/types.h”
#include “kernel/stat.h”
#include “user/user.h”
void* child(int* p)
{
// 关闭上一个进程的写入端
close(p[1]);
int num;
//如果管道为空,说明已经筛选结束,直接关闭读取端,退出即可
if (read(p[0], &num, sizeof(num)) == 0)
{
close(p[0]);
exit(0);
}
//因为筛选规则,管道里面的第一个数一定是质数
printf("prime %d\n", num);
//创建一个管道用来写入这一轮被筛选的数据
int cp[2];
pipe(cp);
//将数据写入子进程中
if (fork() == 0) /
{
//一直递推,形成一种链式结构,让所有不能被当前质数整除的数据(在cp中)传递到下一个进程
child(cp);
}else { //处理从上一个进程收进来的管道数据
close(cp[0]);
int nnum;
//管道数据不会因为读而减少,因此子进程可以循环读,
//将所有不能被当前质数整除的数据传递到孙子进程的管道cp
while(read(p[0], &nnum, sizeof(nnum)))
// process 1 write an number, then process 2 read from the pipe
{
//不能被整除,就放到cp管道
if (nnum % num != 0)
{
write(cp[1], &nnum, sizeof(nnum));
}
}
//关闭cp的写入端
close(cp[1]);
wait(0);
}
exit(0);
}
int main(int argc, char const *argv[])
{
int p[2];
pipe§;
//父进程初始化管道数据,然后用子进程来处理,并以此形成一种链式结构
if (fork() == 0) // child process
{
child(p);
}
else // parent process
{
close(p[0]);
for (int i = 2; i <= 35; i++)
{
write(p[1], &i, sizeof(i));
}
close(p[1]);
wait(0);
}
exit(0);
}
3. 在*Makefile*文件里面UPROGS 添加 $U/\_primes\;
UPROGS=
$U/_cat
$U/_echo
$U/_forktest
$U/_grep
…
$U/_sleep\
$U/_pingpong\
$U/_primes\ //添加进Makefile
4. 直接重新编译***make qemu***,或者用测试脚本测试,我这里就放一下用脚本测试的方法和结果;
jimmy@ubuntu:~/xv6-labs-2020$ ./grade-lab-util primes
make: ‘kernel/kernel’ is up to date.
== Test primes == primes: OK (1.0s)
### find函数
1.这个函数主要是用来找文件的路径,这个和ls命令有很多类似的地方,比如要读取目录树,确定当前是目录还是文件等等。因此,参考ls函数的源码来修改即可.
注意:要求不要对’.‘或者’…'进行递归,而且需要使用strcmp()函数来比较两个字符串。
2.首先写一个函数***basename***,这个函数用来返回一个完整路径下的文件名。(用于这个路径下的文件是不是target文件)
例如:“/home/user/documents/file.txt” -> file.txt
char *basename(char *pathname) {
char *prev = 0;
//分割出以第一个’/‘为结尾的字符串
//cur+1就索引到了’/'之后的第一个字符
char *curr = strchr(pathname, ‘/’);
//循环找,直到找到最后的文件名然后返回
while (curr != 0) {
prev = curr;
curr = strchr(curr + 1, ‘/’);
}
return prev;
}
3.接下来写一个***find***函数,这个函数用于递归查找所有目录里,包含目标字符串的文件,并且打印出来,这个函数就是在ls函数的基础上修改的。
void find(char * curr_path, char * target)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
//当前路径下已经搜索完了或者文件不存在,就返回
if((fd = open(curr_path, 0)) < 0){
fprintf(2, “find: cannot open %s\n”, curr_path);
return;
}
if(fstat(fd, &st) < 0){
fprintf(2, “find: cannot stat %s\n”, curr_path);
close(fd);
return;
}
//判断当前类型
switch(st.type){
//如果是文件,说明搜索到底了
case T_FILE:;
char *file_name = basename(curr_path); //找到文件名
int match = 1;
//如果不是要找的文件名或者为空
if(file_name == 0 || strcmp(file_name+1, target) != 0){
match = 0;
}
//匹配成功,就把当前路径答应出来
if(match){
printf("%s\n",curr_path);
}
close(fd);
break;
//如果是一个目录,说明还要接着递归搜索
case T_DIR:
if(strlen(curr_path) + 1 + DIRSIZ + 1 > sizeof buf){
printf(“find: path too long\n”);
break;
}
strcpy(buf, curr_path);
p = buf+strlen(buf);
*p++ = ‘/’;
while(read(fd, &de, sizeof(de)) == sizeof(de)){
if(de.inum == 0)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if(stat(buf, &st) < 0){
printf(“find: cannot stat %s\n”, buf);
continue;
}
if(strcmp(buf+strlen(buf)-2, “/.”) != 0 && strcmp(buf+strlen(buf)-3, “/…”) != 0) {
find(buf, target); // 递归查找
}
}
break;
}
close(fd);
}
}
4.最后是主函数,只需要做一个参数数目判断,然后调用find函数即可。
int main(int argc, char* argv[])
{
if (argc != 3) {
fprintf(2, “usage: find [directory] [target filename]\n”);
exit(1);
}
find(argv[1], argv[2]);
exit(0);
}
5.在*Makefile*文件里面UPROGS 添加 $U/\_find\;
UPROGS=
$U/_cat
$U/_echo
$U/_forktest
$U/_grep
…
$U/_sleep\
$U/_pingpong\
$U/_primes\
$U/_find\ //添加进Makefile
6. 直接重新编译***make qemu***,或者用测试脚本测试,我这里就放一下用脚本测试的方法和结果;
jimmy@ubuntu:~/xv6-labs-2020$ ./grade-lab-util find
make: ‘kernel/kernel’ is up to date.
== Test find, in current directory == find, in current directory: OK (2.1s)
== Test find, recursive == find, recursive: OK (0.7s)
### xargs函数
1.这个实验是写一个用来传参和执行命令的函数,主要有两个功能:一是可以实现对以’\n’为结尾的指令进行划分,然后执行,二是可以从管道获取其他命令(主要是指标准输入)传过来的参数。举个例子:
$ echo “1\n2” | xargs -n 1 echo line
xrags会将从管道将stdin输入"1\n2"拼接在echo line后:
$ echo line 1
$ \n
$ echo line 2
运行结果为:
$ line 1
$ line 2
2.因此首先定义一个能够执行每个指令的函数***run***,方便调用
//op就是传进来的指令,args是参数
void run(char *op, char **args){
if(fork() == 0){
exec(op,args);
exit(0);
}
return;
}
3.然后写一个能够从管道获取参数,并且拼接参数的主函数
nt main(int argc, char* argv[])
{
char buf[2048]; // 读入时使用的内存池
char *p = buf, *last_p = buf; //当前参数的结束、开始指针
// 全部参数列表,字符串指针数组,包含 argv 传进来的参数和 stdin 读入的参数
char *argsbuf[128];
char **args = argsbuf;
//将 argv 提供的参数加入到最终的参数列表中
//可以用数组的角度去看这是个指针,vector<string> *args = argsbuf[0],*args +1 ...
for(int i = 1; i < argc; i++)
{
*args = argv[i];
args++;
}
// 开始读入从管道传过来的参数,然后根据换行符把相应的参数拼接上去
char **pa = args;
while(read(0, p, 1) != 0) {
if(*p == ' ' || *p == '\n') {
// 读入一个参数完成(以空格分隔,如 `echo hello world`,则 hello 和 world 各为一个参数)
// 读入一行完成,执行指令
if(*p == '\n') {
*pa = 0; // 参数列表末尾用 null 标识列表结束
run(argv[1], argsbuf);
pa = args; // 重置读入参数指针,准备读入下一行
}
*p = '\0';
// 将空格替换为 \0 分割开各个参数,这样可以直接使用内存池中的字符串作为参数字符串
// 而不用额外开辟空间
*(pa++) = last_p;
last_p = p+1;
}
p++;
}
//如果最后一行不是空行,还有未处理的参数
if(pa != args) {
// 收尾最后一个参数
*p = '\0';
*(pa++) = last_p;
// 收尾最后一行
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
args) {
// 收尾最后一个参数
*p = ‘\0’;
*(pa++) = last_p;
// 收尾最后一行
[外链图片转存中…(img-kPEytkaV-1715767441230)]
[外链图片转存中…(img-fcmhjNHU-1715767441231)]
[外链图片转存中…(img-HDNLU68R-1715767441231)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新