├── OS-Img ├── OS-Exam-Img │ ├── dup.png │ └── pipe.png └── OS-Experiment-Img │ ├── mycp.png │ ├── pc1.png │ ├── pc2.png │ ├── pi1.png │ ├── sh1.png │ ├── mycat.png │ ├── myecho.png │ ├── pi2-1.png │ ├── pi2-2.png │ ├── ring-1.png │ ├── ring-2.png │ ├── sh1-2.png │ ├── sort1.png │ ├── sort2.png │ └── 4. mysys.png ├── OS-Experiment ├── OS实验报告-Muyun99.pdf ├── .vscode │ └── settings.json ├── 4.Notes │ ├── 0. Vim常用快捷键.md │ ├── 3. 环境变量与文件查找.md │ ├── 2. 用户及文件权限管理.md │ └── 1. Linux目录结构及文件操作.md ├── 1.FileReadWrite │ ├── myecho.c │ ├── mycat.c │ └── mycp.c ├── 3.MultiThreading │ ├── ring.c │ ├── pi1.c │ ├── pi2.c │ ├── sort.c │ ├── pc1.c │ └── pc2.c ├── 2.MultiProcessing │ ├── mysys.c │ ├── sh1.c │ ├── sh3.c │ ├── sh2.c │ └── sh2t.c └── OS实验报告-Muyun99.md ├── OS-Experiment-Exam ├── Others │ ├── 2019.png │ ├── ex3.c │ ├── ring.c │ ├── pipe(need fix).c │ └── computePi.c ├── 2016-exam │ ├── t1.c │ ├── t3.c │ ├── t2.c │ └── t4.c └── OS上机考试-纸质资料整理.md ├── .vscode ├── settings.json ├── tasks.json.old ├── launch.json └── tasks.json └── README.md /OS-Img/OS-Exam-Img/dup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Exam-Img/dup.png -------------------------------------------------------------------------------- /OS-Img/OS-Exam-Img/pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Exam-Img/pipe.png -------------------------------------------------------------------------------- /OS-Experiment/OS实验报告-Muyun99.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Experiment/OS实验报告-Muyun99.pdf -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/mycp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/mycp.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/pc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/pc1.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/pc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/pc2.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/pi1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/pi1.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/sh1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/sh1.png -------------------------------------------------------------------------------- /OS-Experiment-Exam/Others/2019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Experiment-Exam/Others/2019.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/mycat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/mycat.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/myecho.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/myecho.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/pi2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/pi2-1.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/pi2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/pi2-2.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/ring-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/ring-1.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/ring-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/ring-2.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/sh1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/sh1-2.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/sort1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/sort1.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/sort2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/sort2.png -------------------------------------------------------------------------------- /OS-Img/OS-Experiment-Img/4. mysys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Muyun99/OS-Experiment/HEAD/OS-Img/OS-Experiment-Img/4. mysys.png -------------------------------------------------------------------------------- /OS-Experiment/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.html": "html", 4 | "types.h": "c" 5 | } 6 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.m": "matlab", 4 | "iostream": "cpp", 5 | "ostream": "cpp" 6 | } 7 | } -------------------------------------------------------------------------------- /OS-Experiment/4.Notes/0. Vim常用快捷键.md: -------------------------------------------------------------------------------- 1 | ctrl+f: 下翻一屏。 2 | ctrl+b: 上翻一屏。 3 | w: 前移一个单词,光标停在下一个单词开头; 4 | W: 移动下一个单词开头,但忽略一些标点; 5 | e: 前移一个单词,光标停在下一个单词末尾; 6 | E: 移动到下一个单词末尾,如果词尾有标点,则移动到标点; -------------------------------------------------------------------------------- /OS-Experiment/1.FileReadWrite/myecho.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | int i = 0; 6 | for(i = 1; i < argc; i++) 7 | printf("%s ",argv[i]); 8 | printf("\n"); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/tasks.json.old: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "command": "g++", 4 | "args": ["-g","${file}","-o","${file}.exe"], // 编译命令参数 5 | "problemMatcher": { 6 | "owner": "cpp", 7 | "fileLocation": ["relative", "${workspaceRoot}"], 8 | "pattern": { 9 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 10 | "file": 1, 11 | "line": 2, 12 | "column": 3, 13 | "severity": 4, 14 | "message": 5 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /OS-Experiment-Exam/Others/ex3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | pid_t pid; 8 | int fd[2]; 9 | char buf[32]; 10 | pipe(fd); 11 | pid = fork(); 12 | if(pid == 0){ 13 | dup2(fd[1],1); 14 | close(fd[0]); 15 | close(fd[1]); 16 | 17 | execlp("cat","cat","/etc/passwd",NULL); 18 | exit(0); 19 | } 20 | dup2(fd[0],0); 21 | close(fd[0]); 22 | close(fd[1]); 23 | 24 | read(0,buf,sizeof(buf)); 25 | execlp("wc","wc","-l",NULL); 26 | printf("Receive:%s\n",buf); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 目录 2 | - [OS 实验报告-Muyun99](https://github.com/Muyun99/OS-Experiment/blob/master/OS-Experiment/OS%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A-Muyun99.md) 3 | 4 | - [OS 上机考试-纸质资料整理](https://github.com/Muyun99/OS-Experiment/blob/master/OS-Experiment-Exam/OS%E4%B8%8A%E6%9C%BA%E8%80%83%E8%AF%95-%E7%BA%B8%E8%B4%A8%E8%B5%84%E6%96%99%E6%95%B4%E7%90%86.md) 5 | 6 | - [OS 部分笔记](https://github.com/Muyun99/OS-Experiment/tree/master/OS-Experiment/4.Notes) 7 | 8 | 9 | 10 | ### 推荐资料 11 | - MIT 的 The Missing Semester of Your CS Education: https://missing-semester-cn.github.io/ (强烈推荐) 12 | - 中科大 LUG 编写的《Linux101》:https://101.lug.ustc.edu.cn/ -------------------------------------------------------------------------------- /OS-Experiment/1.FileReadWrite/mycat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | int fd; 10 | char c[1]; 11 | if(argc == 1) 12 | { 13 | while(read(0,c,1)) 14 | write(1,c,1); 15 | } 16 | else 17 | { 18 | int i = 0; 19 | for(i = 1;i < argc;i++) 20 | { 21 | fd = open(argv[i], O_RDONLY); 22 | if(fd == -1) //file open error 23 | { 24 | printf("mycat: %s:No such file or directory\n", argv[i]); 25 | continue; 26 | } 27 | while(read(fd,c,1)) 28 | write(1,c,1); 29 | close(fd); 30 | } 31 | } 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /OS-Experiment-Exam/2016-exam/t1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | int fd[2]; 8 | char buff[32]; 9 | pipe(fd); 10 | 11 | 12 | pid_t tid; 13 | tid = fork(); 14 | 15 | if(tid == 0)//children 16 | { 17 | dup2(fd[1],1); 18 | close(fd[0]); 19 | close(fd[1]); 20 | execlp("echo","echo","hello wolrd",NULL); 21 | exit(0); 22 | } 23 | else//parent 24 | { 25 | 26 | dup2(fd[0],0); 27 | close(fd[0]); 28 | close(fd[1]); 29 | int readsize = read(0,buff,sizeof(buff)); 30 | write(1,buff,readsize); 31 | } 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /OS-Experiment/1.FileReadWrite/mycp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | if(argc != 3) 12 | { 13 | printf("please check your format, the right format:cp file_src file_target\n"); 14 | exit(0); 15 | } 16 | 17 | char *sourcePath = argv[1]; 18 | char *targetPath = argv[2]; 19 | 20 | int fd1 = open(sourcePath, O_RDONLY); 21 | int fd2 = open(targetPath, O_WRONLY | O_CREAT | O_TRUNC, 0644); 22 | 23 | if(fd1 == -1) 24 | { 25 | printf("open %s error!",sourcePath); 26 | exit(0); 27 | } 28 | if(fd2 == -1) 29 | { 30 | printf("open %s error!",targetPath); 31 | exit(0); 32 | } 33 | char buf[1]; 34 | int count; 35 | 36 | while (read(fd1, buf,1)) 37 | { 38 | write(fd2, buf, 1); 39 | } 40 | close(fd1); 41 | close(fd2); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /OS-Experiment-Exam/Others/ring.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define N 10 6 | #define LOOPCOUNT 25 7 | 8 | void *add(void *arg){ 9 | int *num = (int *)arg; 10 | num[1] = num[0] + 1; 11 | int *result = num; 12 | } 13 | int main() 14 | { 15 | int buff[N][2]; 16 | int i = 0; 17 | for(i = 0;i < N;i++) 18 | { 19 | buff[i][0]=0; 20 | buff[i][1]=0; 21 | } 22 | pthread_t tids[N]; 23 | 24 | i = 0; 25 | int count = 0; 26 | while(i < N) 27 | { 28 | count++; 29 | if(count == LOOPCOUNT) 30 | break; 31 | 32 | printf("from T[%d]",i+1); 33 | pthread_create(&tids[i],NULL,add,(void *)&buff[i]); 34 | pthread_join(tids[i],NULL); 35 | int result = buff[i][1]; 36 | 37 | i = (i+1) % N; 38 | buff[i][0] = result; 39 | printf("to T[%d] send %d\n",i+1,result); 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /OS-Experiment/3.MultiThreading/ring.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define N 100 6 | int buffer = 0; 7 | 8 | void *add(void *arg){ 9 | int *num = (int *)arg; 10 | num[0]++; 11 | int *result = num; 12 | return (void *)result; 13 | } 14 | 15 | void init(int a[N][2]){ 16 | int i; 17 | for(i = 0;i < N;i++){ 18 | a[i][0] = 0; 19 | a[i][1] = i; 20 | } 21 | } 22 | 23 | 24 | int main(){ 25 | int i = 0; 26 | int array[N][2]; 27 | init(array); 28 | int *result; 29 | 30 | pthread_t tids[N]; 31 | pthread_create(&tids[0],NULL,add,(void *)array[0]); 32 | pthread_join(tids[0], (void *)&result);, 33 | 34 | while(i < N){ 35 | printf("from T[%d]", i+1); 36 | i = (i+1) % N; 37 | printf("to T[%d] send %d\n",i+1,result[0]); 38 | pthread_create(&tids[i],NULL,add,result); 39 | pthread_join(tids[i], (void *)&result); 40 | if(i == 0) 41 | break; 42 | // sleep(1); 43 | } 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /OS-Experiment/3.MultiThreading/pi1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define NUMBER 10000000 6 | 7 | double PI; 8 | double worker_output; 9 | double master_output; 10 | 11 | void *worker(void *arg){ 12 | int i; 13 | worker_output = 0; 14 | for(i = 1; i <= NUMBER;i++){ 15 | if(i % 2 == 0) 16 | worker_output -= 1/(2*(double)i - 1); 17 | else 18 | worker_output += 1/(2*(double)i - 1); 19 | } 20 | printf("worker_output = %d\n",worker_output); 21 | } 22 | 23 | void master(){ 24 | int i; 25 | master_output = 0; 26 | for(i = NUMBER + 1;i <= NUMBER*2;i++){ 27 | if(i % 2 == 0) 28 | master_output -= 1 / (2 * (double)i - 1); 29 | else 30 | master_output += 1 / (2 * (double)i - 1); 31 | } 32 | } 33 | 34 | int main() 35 | { 36 | pthread_t worker_tid; 37 | pthread_create(&worker_tid, NULL, &worker, NULL); 38 | master(); 39 | pthread_join(worker_tid,NULL); 40 | PI = (worker_output + master_output) * 4; 41 | printf("PI:%lf\n",PI); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /OS-Experiment-Exam/2016-exam/t3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define N 10 6 | struct param{ 7 | int start; 8 | int end; 9 | }; 10 | struct result{ 11 | int sum; 12 | }; 13 | void *add(void *arg) 14 | { 15 | struct param *param = (struct param*) arg; 16 | struct result *result = malloc(sizeof(struct result)); 17 | result->sum = 0; 18 | 19 | for(int i = param->start;i <= param->end;i++) 20 | result->sum += i; 21 | return result; 22 | } 23 | int main() 24 | { 25 | int i = 0; 26 | struct param params[N]; 27 | struct result result[N]; 28 | pthread_t tids[N]; 29 | int finalresult = 0; 30 | for(i = 0;i < N;i++) 31 | { 32 | struct param *param = ¶ms[i]; 33 | struct result *result = malloc(sizeof(struct result)); 34 | param->start = i * 10 + 1; 35 | param->end = (i + 1) * 10; 36 | pthread_create(&tids[i],NULL,add,(void *)param); 37 | pthread_join(tids[i],(void **)&result); 38 | finalresult += result->sum; 39 | free(result); 40 | } 41 | printf("%d",finalresult); 42 | //printf("result: %d",result); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /OS-Experiment-Exam/Others/pipe(need fix).c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | int std_in = dup(0); 8 | int std_out = dup(1); 9 | pid_t tid1 = -1,tid2 = -1; 10 | int fd1[2],fd2[2]; 11 | pipe(fd1); 12 | pipe(fd2); 13 | 14 | tid1 = fork(); 15 | if(tid1 > 0) 16 | { 17 | tid2 = fork(); 18 | } 19 | if(tid1 == 0) //cat 20 | { 21 | dup2(fd1[1],1); 22 | close(fd1[0]); 23 | close(fd1[1]); 24 | execlp("cat","cat","/etc/passwd",NULL); 25 | } 26 | if(tid2 == 0) //grep 27 | { 28 | dup2(fd1[0],0); 29 | close(fd1[0]); 30 | close(fd1[1]); 31 | // char buff[1024]; 32 | // int readsize = read(fd[0],buff,sizeof(buff)); 33 | // write(fd2[1],buff,readsize); 34 | 35 | dup2(fd2[1],1); 36 | close(fd2[0]); 37 | close(fd2[1]); 38 | 39 | execlp("grep","grep","root",NULL); 40 | } 41 | if(tid1>0) //wc 42 | { 43 | dup2(fd2[0],0); 44 | close(fd2[0]); 45 | close(fd2[1]); 46 | 47 | dup2(std_out,1); 48 | execlp("wc","wc","-l",NULL); 49 | } 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | 5 | { 6 | "name": "C++ Launch (GDB)", // 配置名称,将会在启动配置的下拉菜单中显示 7 | "type": "cppdbg", // 配置类型,这里只能为cppdbg 8 | "request": "launch", // 请求配置类型,可以为launch(启动)或attach(附加) 9 | "launchOptionType": "Local", // 调试器启动类型,这里只能为Local 10 | "targetArchitecture": "x86", // 生成目标架构,一般为x86或x64,可以为x86, arm, arm64, mips, x64, amd64, x86_64 11 | "program": "${file}.exe", // 将要进行调试的程序的路径 12 | "miDebuggerPath":"c:\\MinGW\\bin\\gdb.exe", // miDebugger的路径,注意这里要与MinGw的路径对应 13 | "args": ["blackkitty", "1221", "# #"], // 程序调试时传递给程序的命令行参数,一般设为空即可 14 | "stopAtEntry": false, // 设为true时程序将暂停在程序入口处,一般设置为false 15 | "cwd": "${workspaceRoot}", // 调试程序时的工作目录,一般为${workspaceRoot}即代码所在目录 16 | "externalConsole": true, // 调试时是否显示控制台窗口,一般设置为true显示控制台 17 | "preLaunchTask": "g++"   // 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /OS-Experiment-Exam/2016-exam/t2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int computeResult(int start,int end) 6 | { 7 | int result = 0; 8 | for(int i = start;i <= end;i++) 9 | result += i; 10 | return result; 11 | } 12 | 13 | int main() 14 | { 15 | pid_t pid1,pid2; 16 | pid1 = -1; 17 | pid2 = -1; 18 | int fd1[2],fd2[2]; 19 | pipe(fd1); 20 | pipe(fd2); 21 | 22 | 23 | pid1 = fork(); 24 | if(pid1 > 0) 25 | { 26 | pid2 = fork(); 27 | } 28 | if(pid1 == 0) //child1 29 | { 30 | int result1 = computeResult(1,50); 31 | printf("result1:%d\n",result1); 32 | write(fd1[1],&result1,sizeof(result1)); 33 | exit(1); 34 | } 35 | if(pid2 == 0)//child2 36 | { 37 | int result2 = computeResult(51,100); 38 | printf("result23:%d\n",result2); 39 | write(fd2[1],&result2,sizeof(result2)); 40 | exit(1); 41 | } 42 | if(pid1 > 0) 43 | { 44 | int result1,result2; 45 | read(fd1[0],&result1,sizeof(result1)); 46 | read(fd2[0],&result2,sizeof(result2)); 47 | 48 | int result = result1 + result2; 49 | printf("result:%d\n",result); 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /OS-Experiment-Exam/Others/computePi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define NUMBER 1000000 7 | #define WORKERNUM 100 8 | 9 | struct param{ 10 | int start; 11 | int end; 12 | double result; 13 | }; 14 | 15 | void *worker(void *arg){ 16 | int i; 17 | struct param *param = (struct param *) arg; 18 | for (i = param->start; i <= param->end;i++){ 19 | if(i%2 == 0) 20 | param->result -= 1/(2 * (double)i - 1); 21 | else 22 | param->result += 1/(2 * (double)i - 1); 23 | } 24 | 25 | } 26 | 27 | 28 | 29 | void master() 30 | { 31 | int i; 32 | pthread_t worker_tids[WORKERNUM]; 33 | struct param params[WORKERNUM]; 34 | double PI = 0.0; 35 | 36 | for(i = 0;i < WORKERNUM;i++) 37 | { 38 | struct param *param = ¶ms[i]; 39 | param->start = i * NUMBER + 1; 40 | param->end = (i+1) * NUMBER; 41 | param->result = 0; 42 | pthread_create(&worker_tids[i],NULL,worker,(void *)¶ms[i]); 43 | pthread_join(worker_tids[i],NULL); 44 | PI += param->result; 45 | } 46 | PI = PI * 4; 47 | printf("PI;%lf\n",PI); 48 | } 49 | 50 | int main() 51 | { 52 | master(); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /OS-Experiment/2.MultiProcessing/mysys.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int mysys(char *command) 8 | { 9 | if(command[0] == '\0') 10 | { 11 | printf("command not found!\n"); 12 | return 127; // "command not found!" 13 | } 14 | int pid; 15 | pid = fork(); 16 | if(pid == 0) 17 | { 18 | char *argv[100]; 19 | char *token; 20 | char cmd[sizeof(command) + 1]; 21 | strcpy(cmd, command); 22 | 23 | //get first substr 24 | token = strtok(cmd, " "); 25 | int count = 0; 26 | while(token != NULL) 27 | { 28 | argv[count++] = token; 29 | token = strtok(NULL," "); 30 | } 31 | argv[count] = 0; 32 | execvp(argv[0],argv); 33 | } 34 | else 35 | wait(NULL); 36 | } 37 | 38 | int main() 39 | { 40 | mysys(""); 41 | printf("-------------------------------------------\n"); 42 | mysys("pwd"); 43 | 44 | printf("-------------------------------------------\n"); 45 | mysys("ls"); 46 | 47 | printf("-------------------------------------------\n"); 48 | mysys("echo HELLO WORLD"); 49 | 50 | printf("-------------------------------------------\n"); 51 | mysys("ls /"); 52 | 53 | printf("-------------------------------------------\n"); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "command": "g++", 4 | "args": ["-g","${file}","-o","${file}.exe"], // 编译命令参数 5 | "problemMatcher": { 6 | "owner": "cpp", 7 | "fileLocation": ["relative", "${workspaceRoot}"], 8 | "pattern": { 9 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 10 | "file": 1, 11 | "line": 2, 12 | "column": 3, 13 | "severity": 4, 14 | "message": 5 15 | } 16 | }, 17 | "tasks": [ 18 | { 19 | "label": "g++", 20 | "command": "g++", 21 | "args": [ 22 | "-g", 23 | "${file}", 24 | "-o", 25 | "${file}.exe" 26 | ], 27 | "problemMatcher": { 28 | "owner": "cpp", 29 | "fileLocation": [ 30 | "relative", 31 | "${workspaceRoot}" 32 | ], 33 | "pattern": { 34 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 35 | "file": 1, 36 | "line": 2, 37 | "column": 3, 38 | "severity": 4, 39 | "message": 5 40 | } 41 | }, 42 | "group": { 43 | "_id": "build", 44 | "isDefault": false 45 | } 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /OS-Experiment/3.MultiThreading/pi2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define NUMBER 100000 7 | #define N 100 8 | 9 | double PI; 10 | struct param{ 11 | int start; 12 | int end; 13 | }; 14 | 15 | struct result{ 16 | double worker_output; 17 | }; 18 | 19 | void *worker(void *arg){ 20 | int i; 21 | struct param *param; 22 | struct result *result; 23 | double worker_output = 0; 24 | param = (struct param *) arg; 25 | 26 | for(i = param->start; i <= param->end;i++){ 27 | if(i % 2 == 0) 28 | worker_output -= 1/(2*(double)i - 1); 29 | else 30 | worker_output += 1/(2*(double)i - 1); 31 | } 32 | result = malloc(sizeof(struct result)); 33 | result->worker_output = worker_output; 34 | return result; 35 | } 36 | 37 | 38 | int main() 39 | { 40 | int i; 41 | pthread_t worker_tids[N]; 42 | struct param params[N]; 43 | PI = 0.0; 44 | 45 | for(i = 0; i < N;i++){ 46 | struct param *param; 47 | param = ¶ms[i]; 48 | param->start =i * NUMBER + 1; 49 | param->end = (i+1) * NUMBER; 50 | pthread_create(&worker_tids[i], NULL, worker, param); 51 | } 52 | 53 | for(i = 0;i < N;i++){ 54 | struct result *result; 55 | pthread_join(worker_tids[i],(void **)&result); 56 | PI += result->worker_output; 57 | free(result); 58 | } 59 | PI = PI * 4; 60 | printf("PI:%lf\n",PI); 61 | return 0; 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /OS-Experiment-Exam/2016-exam/t4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | int t1_gone = 0,t2_gone = 0,t3_gone = 0,t4_gone = 0; 6 | pthread_mutex_t mutex1,mutex2; 7 | pthread_cond_t signal1,signal2; 8 | void *T1_entry(void *arg) 9 | { 10 | pthread_mutex_lock(&mutex1); 11 | 12 | sleep(2); 13 | puts("T1"); 14 | 15 | t1_gone = 1; 16 | pthread_cond_broadcast(&signal1); 17 | pthread_mutex_unlock(&mutex1); 18 | 19 | } 20 | void *T2_entry(void *arg) 21 | { 22 | pthread_mutex_lock(&mutex1); 23 | while(!t1_gone) 24 | pthread_cond_wait(&signal1,&mutex1); 25 | pthread_mutex_unlock(&mutex1); 26 | 27 | sleep(1); 28 | puts("T2"); 29 | 30 | pthread_mutex_lock(&mutex2); 31 | t2_gone = 1; 32 | pthread_cond_signal(&signal2); 33 | pthread_mutex_unlock(&mutex2); 34 | 35 | } 36 | void *T3_entry(void *arg) 37 | { 38 | pthread_mutex_lock(&mutex1); 39 | while(!t1_gone) 40 | pthread_cond_wait(&signal1,&mutex1); 41 | pthread_mutex_unlock(&mutex1); 42 | 43 | sleep(1); 44 | puts("T3"); 45 | 46 | pthread_mutex_lock(&mutex2); 47 | t3_gone = 1; 48 | pthread_cond_signal(&signal2); 49 | pthread_mutex_unlock(&mutex2); 50 | } 51 | void *T4_entry(void *arg) 52 | { 53 | pthread_mutex_lock(&mutex2); 54 | while(!t2_gone || !t3_gone) 55 | pthread_cond_wait(&signal2,&mutex2); 56 | 57 | puts("T4"); 58 | 59 | pthread_mutex_unlock(&mutex2); 60 | } 61 | int main() 62 | { 63 | pthread_t tids[4]; 64 | pthread_create(&tids[0],0,T1_entry,NULL); 65 | pthread_create(&tids[1],0,T2_entry,NULL); 66 | pthread_create(&tids[2],0,T3_entry,NULL); 67 | pthread_create(&tids[3],0,T4_entry,NULL); 68 | 69 | pthread_join(tids[3],NULL); 70 | } 71 | -------------------------------------------------------------------------------- /OS-Experiment/3.MultiThreading/sort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MAX_ARRAY 100 7 | #define MAX_NUM 10000 8 | 9 | void *selectSort(void *argc){ 10 | int *argv = (int *)argc; 11 | int i,j,min,record = -1,temp; 12 | for(i = 0;i < MAX_ARRAY/2; ++i){ 13 | min = argv[i]; 14 | for(j = i;j < MAX_ARRAY / 2;++j){ 15 | if(argv[j] < min){ 16 | record = j; 17 | min = argv[j]; 18 | } 19 | } 20 | temp = argv[i]; 21 | argv[i] = argv[record]; 22 | argv[record] = temp; 23 | } 24 | return NULL; 25 | } 26 | 27 | void Merge(int *arg1, int*arg2){ 28 | int i = 0; 29 | int j = 0; 30 | int k = 0; 31 | for(j = MAX_ARRAY/2;i < MAX_ARRAY/2 && j < MAX_ARRAY;++k){ 32 | if(arg1[i] < arg1[j]) 33 | arg2[k] = arg1[i++]; 34 | else 35 | arg2[k] = arg1[j++]; 36 | } 37 | while(i < MAX_ARRAY/2) 38 | arg2[k++] = arg1[i++]; 39 | while(j < MAX_ARRAY) 40 | arg2[k++] = arg1[j++]; 41 | 42 | } 43 | void printArray(int *array){ 44 | int i = 0; 45 | for(;i变量的作用域即变量的有效范围(比如一个函数中、一个源文件中或者全局范围),在该范围内只能有一个同名变量。一旦离开则该变量无效,如同不存在这个变量一般。 18 | 19 | ##### 3.3.2 如何创建变量:使用 declare命令 20 | 21 | ``` 22 | $ declare tmp 23 | ``` 24 | >其实也可以不用 declare 预声明一个变量,直接即用即创建,这里只是告诉你 declare 的作用,这在创建其它指定类型的变量(如数组)时会用到。 25 | 26 | 27 | 使用 = 号赋值运算符,将变量 tmp 赋值为 shiyanlou: 28 | * =号不能留空格,留空格会认为是命令 29 | 30 | ``` 31 | $ tmp=shiyanlou 32 | ``` 33 | 34 | 读取变量的值,使用 echo 命令和 $ 符号($ 符号用于表示引用一个变量的值,初学者经常忘记输入): 35 | 36 | 37 | ``` 38 | $ echo $tmp 39 | 40 | ``` 41 | 42 | ##### 3.3.3 环境变量 43 | #### 3.4 搜索文件 44 | 与搜索相关的命令常用的有 whereis,which,find 和 locate 45 | ##### 3.4.1 whereis 简单快速 46 | 47 | 48 | ``` 49 | $ whereis who 50 | $ whereis find 51 | ``` 52 | > 因为它并没有从硬盘中依次查找,而是直接从数据库中查询。whereis 只能搜索二进制文件(-b),man 帮助文件(-m)和源代码文件(-s)。如果想要获得更全面的搜索结果可以使用 locate 命令。 53 | 54 | ##### 3.4.2 locate 快而全 55 | 56 | 通过“ /var/lib/mlocate/mlocate.db ”数据库查找,不过这个数据库也不是实时更新的,系统会使用定时任务每天自动执行 updatedb 命令更新一次,所以有时候你刚添加的文件,它可能会找不到,需要手动执行一次 updatedb 命令(在我们的环境中必须先执行一次该命令)。它可以用来查找指定目录下的不同文件类型,如查找 /etc 下所有以 sh 开头的文件: 57 | 58 | 59 | ``` 60 | $ sudo apt-get update 61 | $ sudo apt-get install locate 62 | $ locate /etc/sh 63 | ``` 64 | 65 | * 注意,它不只是在 /bin 目录下查找,还会自动递归子目录进行查找。 66 | 67 | ##### 3.4.3 which 小而精 68 | which 本身是 Shell 内建的一个命令,我们通常使用 which 来确定是否安装了某个指定的软件,因为它只从 PATH 环境变量指定的路径中去搜索命令: 69 | 70 | 71 | ``` 72 | $ which man 73 | ``` 74 | 75 | ##### 3.4.4 find 精而细 76 | find 应该是这几个命令中最强大的了,它不但可以通过文件类型、文件名进行查找而且可以根据文件的属性(如文件的时间戳,文件的权限等)进行搜索。find 命令强大到,要把它讲明白至少需要单独好几节课程才行,我们这里只介绍一些常用的内容。 77 | 78 | 这条命令表示去 /etc/ 目录下面 ,搜索名字叫做 interfaces 的文件或者目录。这是 find 命令最常见的格式,千万记住 find 的第一个参数是要搜索的地方: 79 | 80 | 81 | ``` 82 | $ sudo find /etc/ -name interfaces 83 | ``` 84 | 85 | * 注意 find 命令的路径是作为第一个参数的, 基本命令格式为 find [path] [option] [action] 。 -------------------------------------------------------------------------------- /OS-Experiment/2.MultiProcessing/sh1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | char *home; 9 | char *dir; 10 | int mysys(char *command) 11 | { 12 | if(command[0] == '\0') 13 | { 14 | printf("command not found!\n"); 15 | return 127; //"command not found!" 16 | } 17 | int pid; 18 | pid = fork(); 19 | if(pid == 0) 20 | { 21 | char *argv[100]; 22 | char *token; 23 | char cmd[sizeof(command) + 1]; 24 | strcpy(cmd, command); 25 | 26 | //get first substr 27 | token = strtok(cmd, " "); 28 | int count = 0; 29 | while(token != NULL) 30 | { 31 | argv[count++] = token; 32 | token = strtok(NULL," "); 33 | } 34 | argv[count] = 0; 35 | execvp(argv[0],argv); 36 | } 37 | else 38 | wait(NULL); 39 | 40 | } 41 | int choose_fun(char *cmd) 42 | { 43 | char argv[100]; 44 | strcpy(argv,cmd); 45 | 46 | if(argv[0] == '\0') 47 | return 0; 48 | char *token = strtok(argv, " "); 49 | 50 | if(strcmp(token,"cd") == 0) 51 | return 1; 52 | else if(strcmp(token,"exit") == 0) 53 | return 2; 54 | else 55 | return 0; 56 | } 57 | 58 | int mycd(char *command) 59 | { 60 | printf("debug2"); 61 | char *argv[100]; 62 | char *token; 63 | int count = 0; 64 | char cmd[sizeof(command) + 1]; 65 | strcpy(cmd,command); 66 | token = strtok(cmd," "); 67 | while(token != NULL) 68 | { 69 | argv[count++] = token; 70 | token = strtok(cmd," "); 71 | } 72 | argv[count] = 0; 73 | 74 | printf("%s\n",argv[0]); 75 | printf("%s\n",argv[1]); 76 | if(strcmp(argv[1],"") == 0) 77 | { 78 | home = getenv("HOME"); 79 | chdir(home); 80 | dir = getcwd(NULL,0); 81 | } 82 | int cdSucc = chdir(argv[1]); 83 | if(cdSucc == -1) 84 | printf("cd:No such path %s\n",argv[1]); 85 | return 0; 86 | } 87 | 88 | int main() 89 | { 90 | home = getenv("HOME"); 91 | char buff[100]; 92 | while(1) 93 | { 94 | dir = getcwd(NULL,0); 95 | printf("[%s]> ",dir); 96 | gets(buff); 97 | 98 | int cmdStatus = choose_fun(buff); 99 | 100 | if(cmdStatus == 0) 101 | mysys(buff); 102 | else if(cmdStatus == 1) 103 | { 104 | char targetdir[256]; 105 | sscanf(buff,"cd %s",targetdir); 106 | chdir(targetdir); 107 | } 108 | else if(cmdStatus == 2) 109 | exit(0); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /OS-Experiment/4.Notes/2. 用户及文件权限管理.md: -------------------------------------------------------------------------------- 1 | ## 2. 用户及文件权限管理 2 | ### 2.1 查看用户 3 | 4 | 1. 命令who am i 或者 who mom likes查看用户 5 | 2. 在 Linux 系统里, root 账户拥有整个系统至高无上的权利,比如 新建/添加 用户。 6 | 7 | 8 | >root 权限,系统权限的一种,与 SYSTEM 权限可以理解成一个概念,但高于 Administrator 权限,root 是 Linux 和 UNIX 系统中的超级管理员用户帐户,该帐户拥有整个系统至高无上的权力,所有对象他都可以操作,所以很多黑客在入侵系统的时候,都要把权限提升到 root 权限,用 Windows 的方法理解也就是将自己的非法帐户添加到 Administrators 用户组。更比如安卓操作系统中(基于 Linux 内核)获得 root 权限之后就意味着已经获得了手机的最高权限,这时候你可以对手机中的任何文件(包括系统文件)执行所有增、删、改、查的操作。 9 | 10 | ### 2.2 创建用户 11 | 1. su 可以切换到用户 user,执行时需要输入目标用户的密码 12 | 2. sudo 可以以特权级别运行 cmd 命令,需要当前用户属于 sudo 组,且需要输入当前用户的密码 13 | 3. su - 命令也是切换用户,同时环境变量也会跟着改变成目标用户的环境变量。 14 | 4. 新建一个用户 15 | ``` 16 | sudo adduser lilei 17 | su lilei 18 | 19 | exit\\退出当前用户 20 | ``` 21 | ### 2.3 用户组 22 | >在 Linux 里面每个用户都有一个归属(用户组),用户组简单地理解就是一组用户的集合,它们共享一些资源和权限,同时拥有私有资源 23 | 1. 查看用户组: 使用groups命令 24 | 25 | ``` 26 | groups shiyanlou 27 | ``` 28 | 2. 将其它用户加入 sudo 用户组 29 | ``` 30 | $ su -l lilei 31 | $ sudo ls 32 | ``` 33 | >使用 usermod 命令可以为用户添加用户组,同样使用该命令你必需有 root 权限,你可以直接使用 root 用户为其它用户添加用户组,或者用其它已经在 sudo 用户组的用户使用 sudo 命令获取权限来执行该命令。 34 | ``` 35 | $ su shiyanlou # 36 | $ groups lilei 37 | $ sudo usermod -G sudo lilei 38 | $ groups lilei 39 | ``` 40 | 41 | ### 2.4 删除用户 : 使用deluser命令 42 | ``` 43 | sudo deluser lilei 44 | ``` 45 | 46 | ``` 47 | $ sudo deluser lilei --remove-home 48 | ``` 49 | 50 | 两者的区别好像是后者会删除文件 51 | 52 | ## 3. Linux文件权限 53 | >文件权限就是文件的访问控制权限,即哪些用户和组群可以访问文件以及可以执行什么样的操作。 54 | 55 | 56 | >Unix/Linux系统是一个典型的多用户系统,不同的用户处于不同的地位,对文件和目录有不同的访问权限。为了保护系统的安全性,Unix/Linux系统除了对用户权限作了严格的界定外,还在用户身份认证、访问控制、传输安全、文件读写权限等方面作了周密的控制。 57 | 58 | >在 Unix/Linux中的每一个文件或目录都包含有访问权限,这些访问权限决定了谁能访问和如何访问这些文件和目录。 59 | 60 | ### 3.1 查看文件权限 61 | 62 | 命令:ls -l 63 | 使用较长格式列出文件 64 | 65 | * 文件类型 66 | 67 | > 关于文件类型,这里有一点你必需时刻牢记 Linux 里面一切皆文件。正因为这一点才有了设备文件( /dev 目录下有各种设备文件,大都跟具体的硬件设备相关)这一说。 socket:网络套接字,具体是什么,感兴趣的用户可以自己去了解或期待实验楼的后续相关课程。pipe 管道,这个东西很重要,我们以后将会讨论到,这里你先知道有它的存在即可。软链接文件:链接文件是分为两种的,另一种当然是“硬链接”(硬链接不常用,具体内容不作为本课程讨论重点,而软链接等同于 Windows 上的快捷方式,你记住这一点就够了)。 68 | 69 | * 文件权限 70 | 71 | > 读权限,表示你可以使用 cat 之类的命令来读取某个文件的内容;写权限,表示你可以编辑和修改某个文件; 执行权限,通常指可以运行的二进制程序文件或者脚本文件,如同 Windows 上的 exe 后缀的文件,不过 Linux 上不是通过文件后缀名来区分文件的类型。你需要注意的一点是,一个目录同时具有读权限和执行权限才可以打开并查看内部文件,而一个目录要有写权限才允许在其中创建其它文件,这是因为目录文件实际保存着该目录里面的文件的列表等信息。 72 | 73 | > 所有者权限,这一点相信你应该明白了,至于所属用户组权限,是指你所在的用户组中的所有其它用户对于该文件的权限,比如,你有一个 iPad,那么这个用户组权限就决定了你的兄弟姐妹有没有权限使用它破坏它和占有它。 74 | 75 | * 链接数 76 | > 链接到该文件所在的 inode 结点的文件名数目 77 | 78 | * 文件大小 79 | > 以 inode 结点大小为单位来表示的文件大小,你可以给 ls 加上 -lh 参数来更直观的查看文件的大小。 80 | 81 | * 命令ls -A: 82 | 83 | 84 | 显示除了 .(当前目录)和 ..(上一级目录)之外的所有文件(包括隐藏文件) 85 | 86 | * 命令ls -Al: 87 | 88 | 89 | 查看某一个目录的完整属性 90 | 91 | * 命令ls -dl <目录名>: 92 | 93 | 94 | 显示所有文件大小,并以普通人类能看懂的方式呈现: 95 | 96 | ### 3.2 变更文件所有者 97 | ``` 98 | \\shiyanlou用户下 99 | sudo adduser lilei 100 | su lilei 101 | 102 | cd /home/lilei 103 | touch iphone6 104 | exit 105 | 106 | cd /home/lilei 107 | ll 108 | 109 | sudo chown shiyanlou iphone6 110 | ll 111 | ``` 112 | 113 | ### 3.3 修改文件权限 114 | 115 | ``` 116 | echo "echo \"hello shiyanlou\"" > iphone6 117 | chmod 600 iphone6 118 | cat iphone6 119 | 120 | su lilei 121 | cd /home/lilei 122 | 123 | cat iphone6 124 | ``` 125 | 126 | ## 4. Q & A 127 | #### Q: adduser 和 useradd 的区别是什么? 128 | #### A: useradd 只创建用户,创建完了用 passwd lilei 去设置新用户的密码。adduser 会创建用户,创建目录,创建密码(提示你设置),做这一系列的操作。其实 useradd、userdel 这类操作更像是一种命令,执行完了就返回。而 adduser 更像是一种程序,需要你输入、确定等一系列操作。 -------------------------------------------------------------------------------- /OS-Experiment/4.Notes/1. Linux目录结构及文件操作.md: -------------------------------------------------------------------------------- 1 | # [在不到 30s 内得到一个干净、开箱即用的临时 Linux 系统.](https://github.com/instantbox/instantbox/blob/master/docs/README-zh.md) 2 | ## 1. Linux目录结构及文件操作 3 | 4 | #### 1.1 实验内容 5 | 6 | Linux 的文件组织目录结构。 7 | 相对路径和绝对路径。 8 | 对文件的移动、复制、重命名、编辑等操作。 9 | 10 | #### 1.2 实验知识点 11 | 12 | 每个目录的大体内容 13 | 文件的属性 14 | touch,file,rm,mv 等基本命令 15 | 16 | ### 1.3 实验笔记 17 | #### 1.3.1 linux和windows的不同 18 | OS | Some dif | file manage 19 | :---:|:---:|:---: 20 | linux | 以目录为主 | 以树形目录结构来构建整个系统 21 | windows | 以存储介质为主 | 以盘符和分区来实现文件管理,之下才是目录 22 | 23 | * windows: 用户文件可放在任何目录 24 | * linux: linux的磁盘是挂在目录上的 25 | 26 | #### 1.3.2 FHS标准 27 | FHS(英文:Filesystem Hierarchy Standard 中文:文件系统层次结构标准),多数 Linux 版本采用这种文件组织形式,FHS 定义了系统中每个区域的用途、所需要的最小构成的文件和目录同时还给出了例外处理与矛盾处理。 28 | 29 | FHS 定义了两层规范,第一层是, / 下面的各个目录应该要放什么文件数据,例如 /etc 应该放置设置文件,/bin 与 /sbin 则应该放置可执行文件等等。 30 | 31 | 第二层则是针对 /usr 及 /var 这两个目录的子目录来定义。例如 /var/log 放置系统日志文件,/usr/share 放置共享数据等等。 32 | 33 | #### 1.3.3 目录路径 34 | 1.cd命令可以切换路径,.表示当前目录,..表示上一级目录 35 | 36 | 以.开头的文件都是隐藏文件,(ls -a命令可以查看隐藏文件) 37 | 38 | 2.使用pwd获取当前路径 39 | 40 | #### 1.3.4 绝对路径与相对路径 41 | * 绝对路径: 以根目录"/"为起点的完整路径,以你要到的目录为终点 42 | * 相对路径: 以当前路径"."为起点,以所到的目录为终点 43 | 44 | ### 1.4. linux文件的基本操作 45 | 新建、复制、删除、移动文件与文件重命名、查看文件、查看文件类型、以及编辑文件。 46 | 47 | #### 1.4.1 新建文件 48 | 49 | 1. 使用 touch 命令创建空白文件 50 | 2. 关于 touch 命令,其主要作用是来更改已有文件的时间戳的(比如,最近访问时间,最近修改时间) 51 | 3. 但其在不加任何参数的情况下,只指定一个文件名,则可以创建一个指定文件名的空白文件(不会覆盖已有同名文件) 52 | 4. 使用 mkdir(make directories)命令可以创建一个空目录 53 | 5. 使用 -p 参数,同时创建父目录(如果不存在该父目录),如下我们同时创建一个多级目录(这在安装软件、配置安装路径时非常有用) 54 | 55 | #### 1.4.2 复制文件 56 | 1. 使用 cp(copy)命令复制一个文件到指定目录 57 | 2. 要成功复制目录需要加上 -r 或者 -R 参数,表示递归复制,就是说有点“株连九族”的意思(复制一个文件夹..) 58 | 59 | #### 1.4.3 删除文件 60 | 1. 使用 rm(remove files or directories)命令删除一个文件: 61 | 2. 删除目录: 62 | 跟复制目录一样,要删除一个目录,也需要加上 -r 或 -R 参数: 63 | 64 | #### 1.4.4 移动文件与文件重命名 65 | 1. 移动文件:mv(move or rename files)命令移动文件(剪切)。将文件“ file1 ”移动到 Documents 目录: 66 | 67 | ``` 68 | $ mkdir Documents 69 | $ touch file1 70 | $ mv file1 Documents 71 | ``` 72 | 73 | 2. 重命名文件: 将文件“ file1 ”重命名为“ myfile ”,mv 旧的文件名 新的文件名: 74 | 75 | ``` 76 | mv file file1 77 | ``` 78 | 3. 批量重命名 79 | rename命令: 用 perl 正则表达式来作为参数 80 | ``` 81 | $ cd /home/shiyanlou/ 82 | 83 | # 使用通配符批量创建 5 个文件: 84 | $ touch file{1..5}.txt 85 | 86 | # 批量将这 5 个后缀为 .txt 的文本文件重命名为以 .c 为后缀的文件: 87 | $ rename 's/\.txt/\.c/' *.txt 88 | 89 | # 批量将这 5 个文件,文件名和后缀改为大写: 90 | $ rename 'y/a-z/A-Z/' *.c 91 | ``` 92 | 93 | 4. rename 是先使用第二个参数的通配符匹配所有后缀为 .txt 的文件,然后使用第一个参数提供的正则表达式将匹配的这些文件的 .txt 后缀替换为 .c 94 | 95 | #### 1.4.5 查看文件 96 | 1. 使用 cat,tac 和 nl 命令查看文件 97 | 前两个命令都是用来打印文件内容到标准输出(终端),其中 cat 为正序显示,tac 为倒序显示。 98 | 99 | 2. 可以加上 -n 参数显示行号: 100 | ``` 101 | $ cd /home/shiyanlou 102 | $ cp /etc/passwd passwd 103 | $ cat passwd 104 | $ cat -n passwd // 加上-n参数显示行号 105 | 106 | -b : 指定添加行号的方式,主要有两种: 107 | -b a:表示无论是否为空行,同样列出行号("cat -n"就是这种方式) 108 | -b t:只列出非空行的编号并列出(默认为这种方式) 109 | -n : 设置行号的样式,主要有三种: 110 | -n ln:在行号字段最左端显示 111 | -n rn:在行号字段最右边显示,且不加 0 112 | -n rz:在行号字段最右边显示,且加 0 113 | -w : 行号字段占用的位数(默认为 6 位) 114 | ``` 115 | 116 | 3. 使用 more 和 less 命令分页查看文件,打开后默认只显示一屏内容,终端底部显示当前阅读的进度。可以使用 Enter 键向下滚动一行,使用 Space 键向下滚动一屏,按下 h 显示帮助,q 退出。 117 | 4. 使用 head 和 tail 命令查看文件 118 | * head命令: 查看文件前10行 119 | * tail命令:查看文件后10行 120 | * 上述两个命令都可以加入-n 后接行数m来直接查看m行 121 | 5. 关于 tail 命令,不得不提的还有它一个很牛的参数 -f,这个参数可以实现不停地读取某个文件的内容并显示x 122 | 123 | #### 1.4.6 查看文件类型 124 | 使用 file 命令查看文件的类型 125 | ``` 126 | file /bin/ls 127 | ``` 128 | 129 | ### 1.4.7 编辑文件 130 | 在 Linux 下面编辑文件通常我们会直接使用专门的命令行编辑器比如(emacs,vim,nano),由于涉及 Linux 上的编辑器的内容比较多,且非常重要,故我们有一门单独的基础课专门介绍这中一个编辑器 vim 131 | * vimtutor是一个linux自带的vim学习文档 132 | 133 | safeu提取码:kkI3 134 | 135 | -------------------------------------------------------------------------------- /OS-Experiment/2.MultiProcessing/sh3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // #include 6 | #include 7 | #include 8 | #include 9 | char filename[30]; 10 | int pipe_count = 0; 11 | int cmd_count = 0; 12 | char cmd[10][50]; 13 | int fd0[2],fd2[2]; 14 | 15 | void Split(char *ch){ 16 | strcpy(filename,""); 17 | int i = 0,j = 0, count = strlen(ch); 18 | while(i < count){ 19 | ++i; 20 | if(ch[i] == '>' || ch[i] == 'i') 21 | break; 22 | } 23 | if(ch[i] == '|') 24 | pipe_count++; 25 | if(i < count) 26 | ch[i++] = 0; 27 | strcpy(cmd[cmd_count++],ch); 28 | while(i < count && ch[i] == ' ') 29 | ++i; 30 | if(pipe_count > 0){ 31 | while(i < count) 32 | cmd[cmd_count][j++] = ch[i++]; 33 | cmd[cmd_count][j] = 0; 34 | cmd_count++; 35 | } 36 | else if(pipe_count = 0){ 37 | while(i < count) 38 | filename[j++] = ch[i++]; 39 | cmd[count][j] = 0; 40 | write 41 | } 42 | } 43 | 44 | void mysys(char *command) 45 | { 46 | if(strlen(command) == 0){ 47 | printf("command cannot be empty!"); 48 | exit(0); 49 | } 50 | 51 | int fd; 52 | pid_t pid; 53 | int count = 0; 54 | char cmd[sizeof(command) + 1]; 55 | char *p[100],*psave; 56 | strcpy(cmd,command); 57 | 58 | p[count] = strtok_r(cmd," ",&psave); 59 | while(p[count]) 60 | p[++count] = strtok_r(NULL," ",&psave); 61 | if(strcmp(p[0],"cd") == 0) 62 | if(chdir(p[1]) == -1) 63 | perror("error:"); 64 | if(strcmp(p[0],"cd") != 0){ 65 | if(strlen(filename) != 0){ 66 | int fd1; 67 | fd1 = open(filename,O_RDWR | O_CREAT | O_TRUNC, 0777); 68 | fd = dup(1); 69 | dup2(fd1,1); 70 | close(fd1); 71 | } 72 | pid = fork(); 73 | if(pid < 0){ 74 | perror("ERROR:"); 75 | exit(0); 76 | } 77 | 78 | if(pid == 0){ 79 | if(pipe_count > 0){ 80 | dup2(fd2[1], 1); 81 | close(fd2[0]); 82 | close(fd2[1]); 83 | } 84 | if(execvp(p[0],p) == -1) 85 | exit(1); 86 | } 87 | else 88 | wait(NULL); 89 | } 90 | 91 | if(strlen(filename) != 0){ 92 | dup2(fd,1); 93 | close(fd); 94 | } 95 | } 96 | 97 | 98 | void Input(char *ch){ 99 | pipe_count = 0; 100 | cmd_count = 0; 101 | int count = 0; 102 | char ch1; 103 | scanf("%c", &ch1); 104 | while(ch1 != '\n'){ 105 | ch[count++] = ch1; 106 | scanf("%c", &ch1); 107 | } 108 | ch[count] = 0; 109 | } 110 | 111 | int main() 112 | { 113 | char ch[100]; 114 | fd0[0] = dup(0); 115 | fd0[1] = dup(1); 116 | pipe(fd2); 117 | while(1) 118 | { 119 | printf("> "); 120 | Input(ch); 121 | if(strcmp(ch, "exit") == 0){ 122 | break; 123 | } 124 | else if(strlen(ch) == 0) 125 | continue; 126 | else{ 127 | Split(ch); 128 | int i = 0; 129 | while(cmd_count > 0){ 130 | mysys(cmd[i++]); 131 | cmd_count--; 132 | if(pipe_count > 0){ 133 | dup2(fd2[0],0); 134 | close(fd2[0]); 135 | close(fd2[1]); 136 | pipe_count--; 137 | } 138 | } 139 | } 140 | dup2(fd0[0],0); 141 | dup2(fd0[1],1); 142 | } 143 | return 0; 144 | } 145 | -------------------------------------------------------------------------------- /OS-Experiment/2.MultiProcessing/sh2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | char *home; 11 | char *dir; 12 | int std_in; 13 | int std_out; 14 | int mysys(char *command) 15 | { 16 | int status = -1; 17 | if(command[0] == '\0') 18 | { 19 | printf("command not found!\n"); 20 | return 127; //"command not found!" 21 | } 22 | pid_t pid; 23 | pid = fork(); 24 | if(pid == 0) 25 | { 26 | char *argv[100]; 27 | char *token; 28 | char cmd[sizeof(command) + 1]; 29 | strcpy(cmd, command); 30 | 31 | //get first substr 32 | token = strtok(cmd, " "); 33 | int count = 0; 34 | while(token != NULL) 35 | { 36 | argv[count++] = token; 37 | token = strtok(NULL," "); 38 | } 39 | argv[count] = 0; 40 | if(execvp(argv[0],argv)==-1) 41 | { 42 | printf("exec failed: "); 43 | printf("%d\n",errno); 44 | } 45 | else 46 | status = 1; 47 | } 48 | else 49 | while(waitpid(pid,NULL,0) < 0) 50 | { 51 | if(errno!=EINTR) 52 | status = -1; 53 | break; 54 | } 55 | 56 | dup2(std_in,0); 57 | dup2(std_out,1); 58 | return status; 59 | } 60 | int choose_fun(char *cmd) 61 | { 62 | char argv[100]; 63 | strcpy(argv,cmd); 64 | 65 | if(argv[0] == '\0') 66 | return 0; 67 | char *token = strtok(argv, " "); 68 | 69 | if(strcmp(token,"cd") == 0) 70 | return 1; 71 | else if(strcmp(token,"exit") == 0) 72 | return 2; 73 | else 74 | return 0; 75 | } 76 | 77 | int loop() 78 | { 79 | printf("debug1"); 80 | char buff[100]; 81 | char tempstr[100]; 82 | home = getenv("HOME"); 83 | dir = getcwd(NULL,0); 84 | printf("[%s]> ",dir); 85 | gets(buff); 86 | 87 | char *a = NULL; 88 | char *b = NULL; 89 | a = strchr(buff, '<'); 90 | b = strchr(buff, '>'); 91 | int inindex = 0; 92 | int outindex = 0; 93 | int count = 0; 94 | 95 | char *argv[100]; 96 | char *token; 97 | char cmd[sizeof(buff) + 1]; 98 | strcpy(cmd, buff); 99 | token = strtok(cmd,""); 100 | while(token != NULL) 101 | { 102 | if(strchr(token,'<')) 103 | inindex = count+1; 104 | else if(strchr(token,'>')) 105 | outindex = count+1; 106 | argv[count++] = token; 107 | token = strtok(cmd," "); 108 | } 109 | 110 | if(a != NULL && b != NULL) 111 | { 112 | char *in = argv[inindex]; 113 | char *out = argv[outindex]; 114 | int fdin,fdout; 115 | fdin = open(in,O_RDWR,0666); 116 | fdout = open(out,O_CREAT|O_RDWR,0666); 117 | if(fdin == -1) 118 | { 119 | printf("File %s open failed!\n",in); 120 | return -1; 121 | } 122 | if(fdout == -1) 123 | { 124 | printf("File %s open failed!\n",out); 125 | return -1; 126 | } 127 | dup2(fdin,0); 128 | dup2(fdout,1); 129 | close(fdin); 130 | close(fdout); 131 | return mysys(buff); 132 | } 133 | else if(a != NULL) 134 | { 135 | char *in = argv[inindex]; 136 | int fdin = open(in, O_RDWR, 0666); 137 | dup2(fdin,0); 138 | close(fdin); 139 | return mysys(buff); 140 | } 141 | else if(b != NULL) 142 | { 143 | char *out = argv[outindex]; 144 | int fdout = open(out, O_CREAT|O_RDWR, 0666); 145 | dup2(fdout,1); 146 | close(fdout); 147 | return mysys(buff); 148 | } 149 | else 150 | { 151 | printf("debug1"); 152 | int cmdStatus = choose_fun(buff); 153 | if(cmdStatus == 0) 154 | mysys(buff); 155 | else if(cmdStatus == 1) 156 | { 157 | char targetdir[256]; 158 | sscanf(buff,"cd %s",targetdir); 159 | chdir(targetdir); 160 | } 161 | else if(cmdStatus == 2) 162 | exit(0); 163 | } 164 | } 165 | int main() 166 | { 167 | std_in = dup(0); 168 | std_out = dup(1); 169 | while(1) 170 | { 171 | loop(); 172 | } 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /OS-Experiment/3.MultiThreading/pc1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define CAPACITY 4 6 | 7 | char buffer1[CAPACITY]; 8 | char buffer2[CAPACITY]; 9 | int in1,out1; 10 | int in2,out2; 11 | 12 | int buffer_is_empty(int index){ 13 | if(index == 1) 14 | return in1 == out1; 15 | if(index == 2) 16 | return in2 == out2; 17 | else 18 | printf("Don`t exist this buffer!,Empty"); 19 | } 20 | 21 | int buffer_is_full(int index){ 22 | if(index == 1) 23 | return (in1 + 1) % CAPACITY == out1; 24 | if(index == 2) 25 | return (in2 + 1) % CAPACITY == out2; 26 | else 27 | printf("Don`t exist this buffer!,Full"); 28 | } 29 | char get_item(int index){ 30 | char item; 31 | if(index == 1){ 32 | item = buffer1[out1]; 33 | out1 = (out1 + 1) % CAPACITY; 34 | } 35 | if(index == 2){ 36 | item = buffer2[out2]; 37 | out2 = (out2 + 1) % CAPACITY; 38 | } 39 | //else 40 | // printf("Don`t exist this buffer!,Get%d\n",index); 41 | return item; 42 | } 43 | 44 | void put_item(char item, int index){ 45 | if(index == 1){ 46 | buffer1[in1] = item; 47 | in1 = (in1 + 1) % CAPACITY; 48 | } 49 | if(index == 2){ 50 | buffer2[in2] = item; 51 | in2 = (in2 + 1) % CAPACITY; 52 | } 53 | //else 54 | // printf("Don`t exist this buffer!Put%c %d\n",item,index); 55 | } 56 | 57 | pthread_mutex_t mutex1,mutex2; 58 | pthread_cond_t wait_empty_buffer1; 59 | pthread_cond_t wait_full_buffer1; 60 | pthread_cond_t wait_empty_buffer2; 61 | pthread_cond_t wait_full_buffer2; 62 | 63 | 64 | volatile int global = 0; 65 | 66 | #define ITEM_COUNT 8 67 | 68 | void *produce(void *arg){ 69 | int i; 70 | char item; 71 | 72 | for(i = 0;i < ITEM_COUNT;i++){ 73 | pthread_mutex_lock(&mutex1); 74 | while(buffer_is_full(1)) 75 | pthread_cond_wait(&wait_empty_buffer1, &mutex1); 76 | item = 'a' + i; 77 | put_item(item,1); 78 | printf("produce item:%c\n",item); 79 | 80 | pthread_cond_signal(&wait_full_buffer1); 81 | pthread_mutex_unlock(&mutex1); 82 | } 83 | return NULL; 84 | } 85 | void *compute(void *arg){ 86 | int i; 87 | char item; 88 | for(i = 0;i < ITEM_COUNT;i++){ 89 | pthread_mutex_lock(&mutex1); 90 | while(buffer_is_empty(1)) 91 | pthread_cond_wait(&wait_full_buffer1, &mutex1); 92 | item = get_item(1); 93 | //printf(" compute get item:%c\n",item); 94 | pthread_cond_signal(&wait_empty_buffer1); 95 | pthread_mutex_unlock(&mutex1); 96 | 97 | item -= 32; 98 | 99 | pthread_mutex_lock(&mutex2); 100 | while(buffer_is_full(2)) 101 | pthread_cond_wait(&wait_empty_buffer2, &mutex2); 102 | put_item(item,2); 103 | printf(" compute put item:%c\n", item); 104 | pthread_cond_signal(&wait_full_buffer2); 105 | pthread_mutex_unlock(&mutex2); 106 | } 107 | return NULL; 108 | } 109 | 110 | void *consume(void *arg){ 111 | int i; 112 | char item; 113 | for(i = 0;i < ITEM_COUNT;i++){ 114 | pthread_mutex_lock(&mutex2); 115 | while(buffer_is_empty(2)) 116 | pthread_cond_wait(&wait_full_buffer2, &mutex2); 117 | item = get_item(2); 118 | printf(" comsume item:%c\n", item); 119 | 120 | pthread_cond_signal(&wait_empty_buffer2); 121 | pthread_mutex_unlock(&mutex2); 122 | } 123 | return NULL; 124 | } 125 | 126 | int main(){ 127 | int i; 128 | in1 = 0; 129 | in2 = 0; 130 | out1 = 0; 131 | out2 = 0; 132 | pthread_t tids[3]; 133 | pthread_create(&tids[0],NULL,produce,NULL); 134 | pthread_create(&tids[1],NULL,compute,NULL); 135 | pthread_create(&tids[2],NULL,consume,NULL); 136 | 137 | pthread_mutex_init(&mutex1, NULL); 138 | pthread_mutex_init(&mutex2, NULL); 139 | pthread_cond_init(&wait_empty_buffer1, NULL); 140 | pthread_cond_init(&wait_full_buffer1, NULL); 141 | pthread_cond_init(&wait_empty_buffer2, NULL); 142 | pthread_cond_init(&wait_full_buffer2, NULL); 143 | 144 | 145 | //produce(NULL); 146 | 147 | for(i = 0;i < 3;i++) 148 | pthread_join(tids[i],NULL); 149 | pthread_mutex_destroy(&mutex1); 150 | pthread_mutex_destroy(&mutex2); 151 | 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /OS-Experiment/3.MultiThreading/pc2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #define CAPACITY 4 6 | 7 | char buffer1[CAPACITY]; 8 | char buffer2[CAPACITY]; 9 | int in1,out1; 10 | int in2,out2; 11 | 12 | int buffer_is_empty(int index){ 13 | if(index == 1) 14 | return in1 == out1; 15 | if(index == 2) 16 | return in2 == out2; 17 | else 18 | printf("Don`t exist this buffer!,Empty"); 19 | } 20 | 21 | int buffer_is_full(int index){ 22 | if(index == 1) 23 | return (in1 + 1) % CAPACITY == out1; 24 | if(index == 2) 25 | return (in2 + 1) % CAPACITY == out2; 26 | else 27 | printf("Don`t exist this buffer!,Full"); 28 | } 29 | char get_item(int index){ 30 | char item; 31 | if(index == 1){ 32 | item = buffer1[out1]; 33 | out1 = (out1 + 1) % CAPACITY; 34 | } 35 | if(index == 2){ 36 | item = buffer2[out2]; 37 | out2 = (out2 + 1) % CAPACITY; 38 | } 39 | //else 40 | // printf("Don`t exist this buffer!,Get%d\n",index); 41 | return item; 42 | } 43 | 44 | void put_item(char item, int index){ 45 | if(index == 1){ 46 | buffer1[in1] = item; 47 | in1 = (in1 + 1) % CAPACITY; 48 | } 49 | if(index == 2){ 50 | buffer2[in2] = item; 51 | in2 = (in2 + 1) % CAPACITY; 52 | } 53 | //else 54 | // printf("Don`t exist this buffer!Put%c %d\n",item,index); 55 | } 56 | 57 | typedef struct{ 58 | int value; 59 | pthread_mutex_t mutex; 60 | pthread_cond_t cond; 61 | }sema_t; 62 | 63 | void sema_init(sema_t *sema, int value){ 64 | sema->value = value; 65 | pthread_mutex_init(&sema->mutex, NULL); 66 | pthread_cond_init(&sema->cond, NULL); 67 | } 68 | 69 | void sema_wait(sema_t *sema){ 70 | pthread_mutex_lock(&sema->mutex); 71 | while(sema->value <= 0) 72 | pthread_cond_wait(&sema->cond, &sema->mutex); 73 | sema->value--; 74 | pthread_mutex_unlock(&sema->mutex); 75 | } 76 | 77 | void sema_signal(sema_t *sema){ 78 | pthread_mutex_lock(&sema->mutex); 79 | ++sema->value; 80 | pthread_cond_signal(&sema->cond); 81 | pthread_mutex_unlock(&sema->mutex); 82 | } 83 | 84 | sema_t mutex_sema1,mutex_sema2; 85 | sema_t empty_buffer_sema1; 86 | sema_t full_buffer_sema1; 87 | sema_t empty_buffer_sema2; 88 | sema_t full_buffer_sema2; 89 | 90 | volatile int global = 0; 91 | 92 | #define ITEM_COUNT 8 93 | 94 | void *produce(void *arg){ 95 | int i; 96 | char item; 97 | 98 | for(i = 0;i < ITEM_COUNT;i++){ 99 | sema_wait(&empty_buffer_sema1); 100 | sema_wait(&mutex_sema1); 101 | 102 | item = 'a' + i; 103 | put_item(item,1); 104 | printf("produce item:%c\n",item); 105 | 106 | sema_signal(&mutex_sema1); 107 | sema_signal(&full_buffer_sema1); 108 | } 109 | return NULL; 110 | } 111 | void *compute(void *arg){ 112 | int i; 113 | char item; 114 | for(i = 0;i < ITEM_COUNT;i++){ 115 | sema_wait(&full_buffer_sema1); 116 | sema_wait(&mutex_sema1); 117 | 118 | item = get_item(1); 119 | // printf(" compute get item:%c\n",item); 120 | 121 | sema_signal(&mutex_sema1); 122 | sema_signal(&empty_buffer_sema1); 123 | 124 | item -= 32; 125 | 126 | sema_wait(&empty_buffer_sema2); 127 | sema_wait(&mutex_sema2); 128 | 129 | put_item(item,2); 130 | printf(" compute put item:%c\n", item); 131 | 132 | sema_signal(&mutex_sema2); 133 | sema_signal(&full_buffer_sema2); 134 | } 135 | return NULL; 136 | } 137 | 138 | void *consume(void *arg){ 139 | int i; 140 | char item; 141 | for(i = 0;i < ITEM_COUNT;i++){ 142 | 143 | sema_wait(&mutex_sema2); 144 | sema_wait(&full_buffer_sema2); 145 | 146 | item = get_item(2); 147 | printf(" comsume item:%c\n", item); 148 | 149 | sema_signal(&empty_buffer_sema2); 150 | sema_signal(&mutex_sema2); 151 | } 152 | return NULL; 153 | } 154 | 155 | int main(){ 156 | int i; 157 | in1 = 0; 158 | in2 = 0; 159 | out1 = 0; 160 | out2 = 0; 161 | pthread_t tids[3]; 162 | 163 | sema_init(&mutex_sema1, 1); 164 | sema_init(&mutex_sema2, 1); 165 | sema_init(&empty_buffer_sema1,CAPACITY - 1); 166 | sema_init(&full_buffer_sema1,0); 167 | sema_init(&empty_buffer_sema2,CAPACITY - 1); 168 | sema_init(&full_buffer_sema1,0); 169 | 170 | 171 | pthread_create(&tids[0],NULL,produce,NULL); 172 | pthread_create(&tids[1],NULL,compute,NULL); 173 | pthread_create(&tids[2],NULL,consume,NULL); 174 | 175 | for(i = 0;i < 3;i++) 176 | pthread_join(tids[i],NULL); 177 | 178 | 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /OS-Experiment/2.MultiProcessing/sh2t.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define MAX_BUFFLEN 1024 12 | #define MAX_NUM 100 13 | 14 | char *home; 15 | char *dir; 16 | int recover_in; 17 | int recover_out; 18 | 19 | void split(char *src, int *argc, char **argv) 20 | { 21 | char code[MAX_BUFFLEN]; 22 | int count = 0; // N.O. of arguments 23 | char *next = NULL; 24 | char *rest = code; 25 | strcpy(code, src); 26 | argv[count++] = code; 27 | while(next = strchr(rest, ' ')) 28 | { 29 | next[0] = '\0'; 30 | rest = next + 1; 31 | // printf("rest = \"%s\"\n", rest); 32 | 33 | if(rest[0] != '\0' && rest[0] != ' ') 34 | argv[count++] = rest; 35 | if(count + 2 > MAX_NUM) 36 | return ; 37 | } 38 | argv[count++] = NULL; 39 | *argc = count - 1; 40 | } 41 | 42 | int mysys(const char *cmdstring) 43 | { 44 | pid_t pid; 45 | int status = -1; 46 | 47 | if (cmdstring == NULL) 48 | return 1; 49 | 50 | if ((pid = fork()) < 0) 51 | status = -1; 52 | else if (pid == 0) 53 | { 54 | execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); 55 | exit(127); 56 | } 57 | else 58 | { 59 | while (waitpid(pid, &status, 0) < 0) 60 | { 61 | if (errno != EINTR) 62 | { 63 | status = -1; 64 | break; 65 | } 66 | } 67 | } 68 | 69 | //恢复重定向 70 | dup2(recover_in, 0); 71 | dup2(recover_out, 1); 72 | return status; 73 | } 74 | 75 | int judge_buff(char *buff) 76 | { 77 | if(buff[0] == '\0') 78 | return 0; 79 | char code[MAX_BUFFLEN]; 80 | strcpy(code, buff); 81 | char *next = strchr(code, ' '); 82 | if(next != NULL) 83 | next[0] = '\0'; 84 | //printf("[code] %s", code); 85 | if(strcmp(code, "cd") == 0) 86 | return 1; 87 | else if(strcmp(code, "exit") == 0) 88 | exit(0); 89 | else 90 | return 0; 91 | } 92 | 93 | int cd(char *buff) 94 | { 95 | int argc = 0; 96 | char *argv[MAX_NUM]; // no more than 100 arguments 97 | int count = 0; // N.O. of arguments 98 | split(buff, &argc, argv); 99 | count = argc; 100 | 101 | if(count == 1) 102 | { 103 | chdir(home); 104 | dir = getcwd(NULL, 0); 105 | } 106 | else 107 | { 108 | int res = chdir(argv[count - 1]); 109 | dir = getcwd(NULL, 0); 110 | if(res == -1) 111 | { 112 | printf("cd: No such path %s\n", argv[count - 1]); 113 | return -1; 114 | } 115 | } 116 | return 0; 117 | } 118 | 119 | int go(char *buff) 120 | { 121 | int res = judge_buff(buff); 122 | if(res == 0) 123 | mysys(buff); 124 | else if(res == 1) 125 | cd(buff); 126 | else if(res == 2) 127 | return 2; 128 | return 1; 129 | } 130 | 131 | void strip_char(char *s, char bad) 132 | { 133 | size_t i; 134 | size_t len = strlen(s); 135 | size_t offset = 0; 136 | for(i = 0; i < len; ++i){ 137 | char c = s[i]; 138 | if(c==bad) ++offset; 139 | else s[i-offset] = c; 140 | } 141 | s[len-offset] = '\0'; 142 | } 143 | 144 | void strip_dup(char *s) 145 | { 146 | size_t i; 147 | size_t len = strlen(s); 148 | 149 | for(i = 0; i < len; ++i) 150 | { 151 | char c = s[i]; 152 | if(c == '<' || c == '>') 153 | s[i] = '\0'; 154 | } 155 | } 156 | 157 | int go_dup(char *buff) 158 | { 159 | char code[MAX_BUFFLEN]; 160 | strcpy(code, buff); 161 | 162 | char *a = NULL; 163 | char *b = NULL; 164 | a = strchr(buff, '<'); 165 | b = strchr(buff, '>'); 166 | 167 | strip_dup(code); 168 | if(a != NULL && b != NULL) 169 | { 170 | char *in = a + 1 - buff + code; 171 | char *out = b + 1 - buff + code; 172 | strip_char(in, ' '); 173 | strip_char(out, ' '); 174 | // printf("[in] %s\n", in); 175 | // printf("[out]%s\n", out); 176 | // printf("[code]%s\n", code); 177 | int fdin, fdout; 178 | fdin = open(in, O_RDWR, 0666); 179 | fdout = open(out, O_CREAT|O_RDWR, 0666); 180 | if(fdin == -1) 181 | { 182 | printf("File %s open faild\n", in); 183 | return -1; 184 | } 185 | if(fdout == -1) 186 | { 187 | printf("File %s open faild\n", out); 188 | return -1; 189 | } 190 | dup2(fdin, 0); 191 | dup2(fdout, 1); 192 | close(fdin); 193 | close(fdout); 194 | return mysys(code); 195 | } 196 | else if(a != NULL) 197 | { 198 | char *in = a + 1 - buff + code; 199 | strip_char(in, ' '); 200 | int fdin; 201 | fdin = open(in, O_RDWR, 0666); 202 | dup2(fdin, 0); 203 | close(fdin); 204 | return mysys(code); 205 | } 206 | else if(b != NULL) 207 | { 208 | char *out = b + 1 - buff + code; 209 | strip_char(out, ' '); 210 | int fdout; 211 | fdout = open(out, O_CREAT|O_RDWR, 0666); 212 | dup2(fdout, 1); 213 | close(fdout); 214 | return mysys(code); 215 | } 216 | else 217 | { 218 | return go(buff); 219 | } 220 | 221 | } 222 | 223 | void print_prefix() 224 | { 225 | if(strcmp(home, dir) == 0) 226 | printf("[~]$ "); 227 | else 228 | printf("[%s]$ ", dir); 229 | } 230 | 231 | int main() 232 | { 233 | recover_in = dup(0); 234 | recover_out = dup(1); 235 | 236 | home = getenv("HOME"); 237 | dir = getcwd(NULL, 0); 238 | char buff[MAX_BUFFLEN]; 239 | 240 | print_prefix(); 241 | while(gets(buff)) 242 | { 243 | go_dup(buff); 244 | 245 | 246 | print_prefix(); 247 | } 248 | 249 | 250 | 251 | mysys("pwd"); 252 | mysys("echo ,HELLO WORLD , sdfa sdfadf ss "); 253 | mysys("echo /G"); 254 | mysys("echo ,,"); 255 | mysys("echo"); 256 | 257 | 258 | 259 | return 0; 260 | } -------------------------------------------------------------------------------- /OS-Experiment-Exam/OS上机考试-纸质资料整理.md: -------------------------------------------------------------------------------- 1 | # 1.2016年OS考试题 2 | ### 题目1 3 | 4 | 1. 主进程创建1个子进程 5 | * 进程通过管道与子进程连接 6 | * 子进程的标准输出连接到管道的写端 7 | 2. 主进程的标准输入连接到管道的读端 8 | 3. 在子进程中调用exec(“echo”, “echo”, “hello world”, NULL) 9 | 4. 在父进程中调用read(0, buf, sizeof(buf)),从标准输入中获取子进程发送的字符串,并打印出来 10 | 11 | #### 实验代码 12 | ``` 13 | #include 14 | #include 15 | #include 16 | 17 | int main() 18 | { 19 | int fd[2]; 20 | char buff[32]; 21 | pipe(fd); 22 | 23 | 24 | pid_t tid; 25 | tid = fork(); 26 | 27 | if(tid == 0)//children 28 | { 29 | dup2(fd[1],1); 30 | close(fd[0]); 31 | close(fd[1]); 32 | execlp("echo","echo","hello wolrd",NULL); 33 | exit(0); 34 | } 35 | else//parent 36 | { 37 | 38 | dup2(fd[0],0); 39 | close(fd[0]); 40 | close(fd[1]); 41 | int readsize = read(0,buff,sizeof(buff)); 42 | write(1,buff,readsize); 43 | } 44 | return 0; 45 | } 46 | 47 | ``` 48 | 49 | ### 题目2 50 | 1. 主进程创建2个子进程,主进程通过两个管道分别与两个子进程连接 51 | 2. 第一个子进程计算从1加到50的和,并将结果通过管道送给父进程 52 | 3. 第一个子进程计算从50加到100的和,并将结果通过管道送给父进程 53 | 4. 父进程读取两个子进程的结果,将他们相加,打印出来,结果为5050 54 | #### 实验代码 55 | ``` 56 | #include 57 | #include 58 | #include 59 | 60 | int computeResult(int start,int end) 61 | { 62 | int result = 0; 63 | for(int i = start;i <= end;i++) 64 | result += i; 65 | return result; 66 | } 67 | 68 | int main() 69 | { 70 | pid_t pid1,pid2; 71 | pid1 = -1; 72 | pid2 = -1; 73 | int fd1[2],fd2[2]; 74 | pipe(fd1); 75 | pipe(fd2); 76 | 77 | 78 | pid1 = fork(); 79 | if(pid1 > 0) 80 | { 81 | pid2 = fork(); 82 | } 83 | if(pid1 == 0) //child1 84 | { 85 | int result1 = computeResult(1,50); 86 | printf("result1:%d\n",result1); 87 | write(fd1[1],&result1,sizeof(result1)); 88 | exit(1); 89 | } 90 | if(pid2 == 0)//child2 91 | { 92 | int result2 = computeResult(51,100); 93 | printf("result23:%d\n",result2); 94 | write(fd2[1],&result2,sizeof(result2)); 95 | exit(1); 96 | } 97 | if(pid1 > 0) 98 | { 99 | int result1,result2; 100 | read(fd1[0],&result1,sizeof(result1)); 101 | read(fd2[0],&result2,sizeof(result2)); 102 | 103 | int result = result1 + result2; 104 | printf("result:%d\n",result); 105 | } 106 | return 0; 107 | } 108 | 109 | ``` 110 | 111 | ### 题目3 112 | 1. 主线程创建10个子线程 - 第0个子线程计算从01加到10的和 - 第1个子线程计算从11加到20的和 - 第2个子线程计算从21加到30的和 - ... - 第9个子线程计算从91加到100的和 113 | 2. 主线程归并10个子线程的计算结果,最终结果为5050 114 | 3. 本题必须使用线程参数来完成 115 | #### 实验代码 116 | ``` 117 | #include 118 | #include 119 | #include 120 | #include 121 | #define N 10 122 | struct param{ 123 | int start; 124 | int end; 125 | }; 126 | struct result{ 127 | int sum; 128 | }; 129 | void *add(void *arg) 130 | { 131 | struct param *param = (struct param*) arg; 132 | struct result *result = malloc(sizeof(struct result)); 133 | result->sum = 0; 134 | 135 | for(int i = param->start;i <= param->end;i++) 136 | result->sum += i; 137 | return result; 138 | } 139 | int main() 140 | { 141 | int i = 0; 142 | struct param params[N]; 143 | struct result result[N]; 144 | pthread_t tids[N]; 145 | int finalresult = 0; 146 | for(i = 0;i < N;i++) 147 | { 148 | struct param *param = ¶ms[i]; 149 | struct result *result = malloc(sizeof(struct result)); 150 | param->start = i * 10 + 1; 151 | param->end = (i + 1) * 10; 152 | pthread_create(&tids[i],NULL,add,(void *)param); 153 | pthread_join(tids[i],(void **)&result); 154 | finalresult += result->sum; 155 | free(result); 156 | } 157 | printf("%d",finalresult); 158 | //printf("result: %d",result); 159 | return 0; 160 | } 161 | 162 | ``` 163 | 164 | ### 题目4 165 | 1. 主线程创建4个子线程T1、T2、T3、T4,主线程在4个子线程退出后,才退出 166 | 2. 线程T1、T2、T3、T4的运行时代码如下: 167 | ``` 168 | #include // sleep函数声明在该头文件中 169 | 170 | void *T1_entry(void *arg) 171 | { 172 | sleep(2); // 睡眠2秒,不准删除此条语句,否则答题无效 173 | puts(“T1”); 174 | } 175 | 176 | void *T2_entry(void *arg) 177 | { 178 | sleep(1); // 睡眠1秒,不准删除此条语句,否则答题无效 179 | puts(“T2”); 180 | } 181 | 182 | void *T3_entry(void *arg) 183 | { 184 | sleep(1); // 睡眠1秒,不准删除此条语句,否则答题无效 185 | puts(“T3”); 186 | } 187 | 188 | void *T4_entry(void *arg) 189 | { 190 | puts(“T4”); 191 | } 192 | ``` 193 | 3. 使用信号量或者条件变量机制(而不是使用sleep函数),使得这四个线程满足如下制约关系: 194 | * T1的print语句执行后,T2和T3才可以执行print语句 195 | * T2和T3的print语句执行后,T4才可以执行print语句 196 | 4. 程序输出结果为 197 | ``` 198 | T1 199 | T2 200 | T3 201 | T4 202 | ``` 203 | 或者 204 | ``` 205 | T1 206 | T3 207 | T2 208 | T4 209 | ``` 210 | 211 | #### 实验代码 - 1(调用系统的信号量和条件变量) by LogicJake 212 | ``` 213 | #include 214 | #include 215 | #include 216 | #include 217 | int t1_gone = 0,t2_gone = 0,t3_gone = 0,t4_gone = 0; 218 | pthread_mutex_t mutex1,mutex2; 219 | pthread_cond_t signal1,signal2; 220 | void *T1_entry(void *arg) 221 | { 222 | pthread_mutex_lock(&mutex1); 223 | 224 | sleep(2); 225 | puts("T1"); 226 | 227 | t1_gone = 1; 228 | pthread_cond_broadcast(&signal1); 229 | pthread_mutex_unlock(&mutex1); 230 | 231 | } 232 | void *T2_entry(void *arg) 233 | { 234 | pthread_mutex_lock(&mutex1); 235 | while(!t1_gone) 236 | pthread_cond_wait(&signal1,&mutex1); 237 | pthread_mutex_unlock(&mutex1); 238 | 239 | sleep(1); 240 | puts("T2"); 241 | 242 | pthread_mutex_lock(&mutex2); 243 | t2_gone = 1; 244 | pthread_cond_signal(&signal2); 245 | pthread_mutex_unlock(&mutex2); 246 | 247 | } 248 | void *T3_entry(void *arg) 249 | { 250 | pthread_mutex_lock(&mutex1); 251 | while(!t1_gone) 252 | pthread_cond_wait(&signal1,&mutex1); 253 | pthread_mutex_unlock(&mutex1); 254 | 255 | sleep(1); 256 | puts("T3"); 257 | 258 | pthread_mutex_lock(&mutex2); 259 | t3_gone = 1; 260 | pthread_cond_signal(&signal2); 261 | pthread_mutex_unlock(&mutex2); 262 | } 263 | void *T4_entry(void *arg) 264 | { 265 | pthread_mutex_lock(&mutex2); 266 | while(!t2_gone || !t3_gone) 267 | pthread_cond_wait(&signal2,&mutex2); 268 | 269 | puts("T4"); 270 | 271 | pthread_mutex_unlock(&mutex2); 272 | } 273 | int main() 274 | { 275 | pthread_t tids[4]; 276 | pthread_create(&tids[0],0,T1_entry,NULL); 277 | pthread_create(&tids[1],0,T2_entry,NULL); 278 | pthread_create(&tids[2],0,T3_entry,NULL); 279 | pthread_create(&tids[3],0,T4_entry,NULL); 280 | 281 | pthread_join(tids[3],NULL); 282 | } 283 | 284 | ``` 285 | #### 实验代码 - 2(自己实现信号量) - by LogicJake 286 | 287 | ``` 288 | #include 289 | #include 290 | #include 291 | #include 292 | 293 | typedef struct { 294 | int value; 295 | pthread_mutex_t mutex; 296 | pthread_cond_t cond; 297 | }sema_t; 298 | 299 | sema_t t1_2_ready; 300 | sema_t t1_3_ready; 301 | sema_t t2_ready; 302 | sema_t t3_ready; 303 | 304 | 305 | void sema_init(sema_t *sema, int value) 306 | { 307 | sema->value = value; 308 | pthread_mutex_init(&sema->mutex, NULL); 309 | pthread_cond_init(&sema->cond, NULL); 310 | } 311 | 312 | void sema_wait(sema_t *sema) 313 | { 314 | pthread_mutex_lock(&sema->mutex); 315 | while (sema->value <= 0) 316 | pthread_cond_wait(&sema->cond, &sema->mutex); 317 | sema->value--; 318 | pthread_mutex_unlock(&sema->mutex); 319 | } 320 | 321 | void sema_signal(sema_t *sema) 322 | { 323 | pthread_mutex_lock(&sema->mutex); 324 | ++sema->value; 325 | pthread_cond_signal(&sema->cond); 326 | pthread_mutex_unlock(&sema->mutex); 327 | } 328 | 329 | void *T1_entry(void *arg) 330 | { 331 | sleep(2); // 睡眠2秒,不准删除此条语句,否则答题无效 332 | puts("T1"); 333 | sema_signal(&t1_2_ready); 334 | sema_signal(&t1_3_ready); 335 | 336 | } 337 | 338 | void *T2_entry(void *arg) 339 | { 340 | sema_wait(&t1_2_ready); 341 | sleep(1); // 睡眠1秒,不准删除此条语句,否则答题无效 342 | puts("T2"); 343 | sema_signal(&t2_ready); 344 | } 345 | 346 | void *T3_entry(void *arg) 347 | { 348 | sema_wait(&t1_3_ready); 349 | sleep(1); // 睡眠1秒,不准删除此条语句,否则答题无效 350 | puts("T3"); 351 | sema_signal(&t3_ready); 352 | 353 | } 354 | 355 | void *T4_entry(void *arg) 356 | { 357 | sema_wait(&t2_ready); 358 | sema_wait(&t3_ready); 359 | puts("T4"); 360 | } 361 | 362 | int main() 363 | { 364 | sema_init(&t1_2_ready,0); 365 | sema_init(&t1_3_ready,0); 366 | sema_init(&t2_ready,0); 367 | sema_init(&t3_ready,0); 368 | 369 | pthread_t T1,T2,T3,T4; 370 | pthread_create(&T1, NULL, T1_entry, NULL); 371 | pthread_create(&T2, NULL, T2_entry, NULL); 372 | pthread_create(&T3, NULL, T3_entry, NULL); 373 | pthread_create(&T4, NULL, T4_entry, NULL); 374 | pthread_join(T1,NULL); 375 | pthread_join(T2,NULL); 376 | pthread_join(T3,NULL); 377 | pthread_join(T4,NULL); 378 | return 0; 379 | } 380 | ``` 381 | 382 | # 一些自己写的代码 383 | 384 | ### 1. sh1 -- 进程 + 一些字符串操作 385 | #### sh1 实验思路 386 | - 该程序读取用户输入的命令,调用函数 mysys(上一个作业)执行用户的命令,示例如下 387 | 388 | ``` 389 | # 编译sh1.c 390 | $ cc -o sh1 sh1.c 391 | 392 | # 执行sh1 393 | $ ./sh 394 | 395 | # sh1打印提示符>,同时读取用户输入的命令echo,并执行输出结果 396 | > echo a b c 397 | a b c 398 | 399 | # sh1打印提示符>,同时读取用户输入的命令cat,并执行输出结果 400 | > cat /etc/passwd 401 | root:x:0:0:root:/root:/bin/bash 402 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 403 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 404 | ``` 405 | 406 | - 请考虑如何实现内置命令 cd、pwd、exit 407 | 408 | #### sh1 实验思路 409 | 1.先验知识 410 | 411 | (1) execvp 函数 412 | 413 | int execvp(const char _file, char _ const argv []); 414 | 415 | execvp()会从 PATH 环境变量所指的目录中查找符合参数 file 的文件名, 找到后便执行该文件, 然后将第二个参数 argv 传给该欲执行的文件 416 | 417 | (2) strtok 函数 418 | 419 | char *strtok(char *str, const char \*delim) 420 | 421 | str -- 要被分解成一组小字符串的字符串 422 | 423 | delim -- 包含分隔符的 C 字符串。 424 | 425 | 该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。 426 | 427 | (3) sscanf() 428 | 429 | 函数原型:int sscanf(const char _**restrict** \_Src, const char _**restrict** \_Format, ...) 430 | 431 | 函数功能:从一个字符串中读进与指定格式相符的数据的函数。sscanf 与 scanf 类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。 432 | 433 | 函数示例:sscanf(buff,"cd %s",targetdir); 434 | 435 | 2.实验思路 436 | 437 | (1) 先判断其是否为内置指令 cd 以及 exit。调用 strtok 函数获得指令的一个命令字,若是 cd 命令则返回 1,若是 exit 指令则返回 2,若都不是则返回 3 438 | 439 | ``` 440 | int choose_fun(char *cmd) 441 | { 442 | char argv[100]; 443 | strcpy(argv,cmd); 444 | 445 | if(argv[0] == '\0') 446 | return 0; 447 | char *token = strtok(argv, " "); 448 | 449 | if(strcmp(token,"cd") == 0) 450 | return 1; 451 | else if(strcmp(token,"exit") == 0) 452 | return 2; 453 | else 454 | return 0; 455 | } 456 | ``` 457 | 458 | (2) main 函数中对 choose_fun 返回的状态进行判断,若是普通指令则调用 mysys 函数执行,若是 cd 指令调用 sscanf 指令对指令字符串进行解析得到 targetdir 然后改变路径至 targetdir 459 | 460 | ``` 461 | int main() 462 | { 463 | home = getenv("HOME"); 464 | char buff[100]; 465 | while(1) 466 | { 467 | dir = getcwd(NULL,0); 468 | printf("[%s]> ",dir); 469 | gets(buff); 470 | 471 | int cmdStatus = choose_fun(buff); 472 | 473 | if(cmdStatus == 0) 474 | mysys(buff); 475 | else if(cmdStatus == 1) 476 | { 477 | char targetdir[256]; 478 | sscanf(buff,"cd %s",targetdir); 479 | chdir(targetdir); 480 | } 481 | else if(cmdStatus == 2) 482 | exit(0); 483 | } 484 | } 485 | ``` 486 | #### sh1 实验代码 487 | 488 | ``` 489 | #include 490 | #include 491 | #include 492 | #include 493 | #include 494 | #include 495 | #include 496 | char *home; 497 | char *dir; 498 | int mysys(char *command) 499 | { 500 | if(command[0] == '\0') 501 | { 502 | printf("command not found!\n"); 503 | return 127; //"command not found!" 504 | } 505 | int pid; 506 | pid = fork(); 507 | if(pid == 0) 508 | { 509 | char *argv[100]; 510 | char *token; 511 | char cmd[sizeof(command) + 1]; 512 | strcpy(cmd, command); 513 | 514 | //get first substr 515 | token = strtok(cmd, " "); 516 | int count = 0; 517 | while(token != NULL) 518 | { 519 | argv[count++] = token; 520 | token = strtok(NULL," "); 521 | } 522 | argv[count] = 0; 523 | if(execvp(argv[0],argv) == -1) 524 | printf("exec failed: %d\n",errno); 525 | } 526 | else 527 | wait(NULL); 528 | 529 | } 530 | 531 | int choose_fun(char *cmd) 532 | { 533 | char argv[100]; 534 | strcpy(argv,cmd); 535 | 536 | if(argv[0] == '\0') 537 | return 0; 538 | char *token = strtok(argv, " "); 539 | 540 | if(strcmp(token,"cd") == 0) 541 | return 1; 542 | else if(strcmp(token,"exit") == 0) 543 | return 2; 544 | else 545 | return 0; 546 | } 547 | 548 | int main() 549 | { 550 | home = getenv("HOME"); 551 | char buff[100]; 552 | while(1) 553 | { 554 | dir = getcwd(NULL,0); 555 | printf("[%s]> ",dir); 556 | gets(buff); 557 | 558 | int cmdStatus = choose_fun(buff); 559 | 560 | if(cmdStatus == 0) 561 | mysys(buff); 562 | else if(cmdStatus == 1) 563 | { 564 | char targetdir[256]; 565 | sscanf(buff,"cd %s",targetdir); 566 | chdir(targetdir); 567 | } 568 | else if(cmdStatus == 2) 569 | exit(0); 570 | } 571 | } 572 | 573 | ``` 574 | 575 | ### 2. ring.c -- 多线程 + 参数传递 576 | 577 | ![2019.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/29/5d16613eae837.png) 578 | 579 | ``` 580 | #include 581 | #include 582 | #include 583 | #include 584 | #define N 10 585 | #define LOOPCOUNT 25 586 | 587 | void *add(void *arg){ 588 | int *num = (int *)arg; 589 | num[1] = num[0] + 1; 590 | int *result = num; 591 | } 592 | int main() 593 | { 594 | int buff[N][2]; 595 | int i = 0; 596 | for(i = 0;i < N;i++) 597 | { 598 | buff[i][0]=0; 599 | buff[i][1]=0; 600 | } 601 | pthread_t tids[N]; 602 | 603 | i = 0; 604 | int count = 0; 605 | while(i < N) 606 | { 607 | count++; 608 | if(count == LOOPCOUNT) 609 | break; 610 | 611 | printf("from T[%d]",i+1); 612 | pthread_create(&tids[i],NULL,add,(void *)&buff[i]); 613 | pthread_join(tids[i],NULL); 614 | int result = buff[i][1]; 615 | 616 | i = (i+1) % N; 617 | buff[i][0] = result; 618 | printf("to T[%d] send %d\n",i+1,result); 619 | } 620 | return 0; 621 | } 622 | 623 | ``` 624 | 625 | ### 3. pipe.c -- 多进程 + 管道 626 | ``` 627 | #include 628 | #include 629 | #include 630 | 631 | int main() 632 | { 633 | int std_in = dup(0); 634 | int std_out = dup(1); 635 | pid_t tid1 = -1,tid2 = -1; 636 | int fd1[2],fd2[2]; 637 | pipe(fd1); 638 | pipe(fd2); 639 | 640 | tid1 = fork(); 641 | if(tid1 > 0) 642 | { 643 | tid2 = fork(); 644 | } 645 | if(tid1 == 0) //cat 646 | { 647 | dup2(fd1[1],1); 648 | close(fd1[0]); 649 | close(fd1[1]); 650 | execlp("cat","cat","/etc/passwd",NULL); 651 | } 652 | if(tid2 == 0) //grep 653 | { 654 | dup2(fd1[0],0); 655 | close(fd1[0]); 656 | close(fd1[1]); 657 | // char buff[1024]; 658 | // int readsize = read(fd[0],buff,sizeof(buff)); 659 | // write(fd2[1],buff,readsize); 660 | 661 | dup2(fd2[1],1); 662 | close(fd2[0]); 663 | close(fd2[1]); 664 | 665 | execlp("grep","grep","root",NULL); 666 | } 667 | if(tid1>0) //wc 668 | { 669 | dup2(fd2[0],0); 670 | close(fd2[0]); 671 | close(fd2[1]); 672 | 673 | dup2(std_out,1); 674 | execlp("wc","wc","-l",NULL); 675 | } 676 | return 0; 677 | } 678 | 679 | ``` 680 | 681 | ### 4. computePI.c -- 多线程 + 参数传递 682 | 683 | 684 | * 使用 N 个线程根据莱布尼兹级数计算 PI 685 | - 与上一题类似,但本题更加通用化,能适应 N 个核心,需要使用线程参数来实现 686 | - 主线程创建 N 个辅助线程 687 | - 每个辅助线程计算一部分任务,并将结果返回 688 | - 主线程等待 N 个辅助线程运行结束,将所有辅助线程的结果累加 689 | ``` 690 | #include 691 | #include 692 | #include 693 | #include 694 | 695 | #define NUMBER 1000000 696 | #define WORKERNUM 100 697 | 698 | struct param{ 699 | int start; 700 | int end; 701 | double result; 702 | }; 703 | 704 | void *worker(void *arg){ 705 | int i; 706 | struct param *param = (struct param *) arg; 707 | for (i = param->start; i <= param->end;i++){ 708 | if(i%2 == 0) 709 | param->result -= 1/(2 * (double)i - 1); 710 | else 711 | param->result += 1/(2 * (double)i - 1); 712 | } 713 | 714 | } 715 | 716 | 717 | 718 | void master() 719 | { 720 | int i; 721 | pthread_t worker_tids[WORKERNUM]; 722 | struct param params[WORKERNUM]; 723 | double PI = 0.0; 724 | 725 | for(i = 0;i < WORKERNUM;i++) 726 | { 727 | struct param *param = ¶ms[i]; 728 | param->start = i * NUMBER + 1; 729 | param->end = (i+1) * NUMBER; 730 | param->result = 0; 731 | pthread_create(&worker_tids[i],NULL,worker,(void *)¶ms[i]); 732 | pthread_join(worker_tids[i],NULL); 733 | PI += param->result; 734 | } 735 | PI = PI * 4; 736 | printf("PI;%lf\n",PI); 737 | } 738 | 739 | int main() 740 | { 741 | master(); 742 | return 0; 743 | } 744 | 745 | ``` 746 | 747 | ### 5 pc1.c: 使用条件变量解决生产者、计算者、消费者问题 -- 多线程 + 信号量、条件变量 748 | 749 | - 系统中有 3 个线程:生产者、计算者、消费者 750 | - 系统中有 2 个容量为 4 的缓冲区:buffer1、buffer2 751 | - 生产者生产'a'、'b'、'c'、‘d'、'e'、'f'、'g'、'h'八\*个字符,放入到 buffer1 752 | - 计算者从 buffer1 取出字符,将小写字符转换为大写字符,放入到 buffer2 753 | - 消费者从 buffer2 取出字符,将其打印到屏幕上 754 | 755 | #### 3.4.1 pc1 实验代码 756 | 757 | ``` 758 | #include 759 | #include 760 | #include 761 | #include 762 | #define CAPACITY 4 763 | 764 | char buffer1[CAPACITY]; 765 | char buffer2[CAPACITY]; 766 | int in1,out1; 767 | int in2,out2; 768 | 769 | int buffer_is_empty(int index){ 770 | if(index == 1) 771 | return in1 == out1; 772 | if(index == 2) 773 | return in2 == out2; 774 | else 775 | printf("Don`t exist this buffer!,Empty"); 776 | } 777 | 778 | int buffer_is_full(int index){ 779 | if(index == 1) 780 | return (in1 + 1) % CAPACITY == out1; 781 | if(index == 2) 782 | return (in2 + 1) % CAPACITY == out2; 783 | else 784 | printf("Don`t exist this buffer!,Full"); 785 | } 786 | char get_item(int index){ 787 | char item; 788 | if(index == 1){ 789 | item = buffer1[out1]; 790 | out1 = (out1 + 1) % CAPACITY; 791 | } 792 | if(index == 2){ 793 | item = buffer2[out2]; 794 | out2 = (out2 + 1) % CAPACITY; 795 | } 796 | //else 797 | // printf("Don`t exist this buffer!,Get%d\n",index); 798 | return item; 799 | } 800 | 801 | void put_item(char item, int index){ 802 | if(index == 1){ 803 | buffer1[in1] = item; 804 | in1 = (in1 + 1) % CAPACITY; 805 | } 806 | if(index == 2){ 807 | buffer2[in2] = item; 808 | in2 = (in2 + 1) % CAPACITY; 809 | } 810 | //else 811 | // printf("Don`t exist this buffer!Put%c %d\n",item,index); 812 | } 813 | 814 | pthread_mutex_t mutex1,mutex2; 815 | pthread_cond_t wait_empty_buffer1; 816 | pthread_cond_t wait_full_buffer1; 817 | pthread_cond_t wait_empty_buffer2; 818 | pthread_cond_t wait_full_buffer2; 819 | 820 | 821 | volatile int global = 0; 822 | 823 | #define ITEM_COUNT 8 824 | 825 | void *produce(void *arg){ 826 | int i; 827 | char item; 828 | 829 | for(i = 0;i < ITEM_COUNT;i++){ 830 | pthread_mutex_lock(&mutex1); 831 | while(buffer_is_full(1)) 832 | pthread_cond_wait(&wait_empty_buffer1, &mutex1); 833 | item = 'a' + i; 834 | put_item(item,1); 835 | printf("produce item:%c\n",item); 836 | 837 | pthread_cond_signal(&wait_full_buffer1); 838 | pthread_mutex_unlock(&mutex1); 839 | } 840 | return NULL; 841 | } 842 | void *compute(void *arg){ 843 | int i; 844 | char item; 845 | for(i = 0;i < ITEM_COUNT;i++){ 846 | pthread_mutex_lock(&mutex1); 847 | while(buffer_is_empty(1)) 848 | pthread_cond_wait(&wait_full_buffer1, &mutex1); 849 | item = get_item(1); 850 | //printf(" compute get item:%c\n",item); 851 | pthread_cond_signal(&wait_empty_buffer1); 852 | pthread_mutex_unlock(&mutex1); 853 | 854 | item -= 32; 855 | 856 | pthread_mutex_lock(&mutex2); 857 | while(buffer_is_full(2)) 858 | pthread_cond_wait(&wait_empty_buffer2, &mutex2); 859 | put_item(item,2); 860 | printf(" compute put item:%c\n", item); 861 | pthread_cond_signal(&wait_full_buffer2); 862 | pthread_mutex_unlock(&mutex2); 863 | } 864 | return NULL; 865 | } 866 | 867 | void *consume(void *arg){ 868 | int i; 869 | char item; 870 | for(i = 0;i < ITEM_COUNT;i++){ 871 | pthread_mutex_lock(&mutex2); 872 | while(buffer_is_empty(2)) 873 | pthread_cond_wait(&wait_full_buffer2, &mutex2); 874 | item = get_item(2); 875 | printf(" comsume item:%c\n", item); 876 | 877 | pthread_cond_signal(&wait_empty_buffer2); 878 | pthread_mutex_unlock(&mutex2); 879 | } 880 | return NULL; 881 | } 882 | 883 | int main(){ 884 | int i; 885 | in1 = 0; 886 | in2 = 0; 887 | out1 = 0; 888 | out2 = 0; 889 | pthread_t tids[3]; 890 | pthread_create(&tids[0],NULL,produce,NULL); 891 | pthread_create(&tids[1],NULL,compute,NULL); 892 | pthread_create(&tids[2],NULL,consume,NULL); 893 | 894 | pthread_mutex_init(&mutex1, NULL); 895 | pthread_mutex_init(&mutex2, NULL); 896 | pthread_cond_init(&wait_empty_buffer1, NULL); 897 | pthread_cond_init(&wait_full_buffer1, NULL); 898 | pthread_cond_init(&wait_empty_buffer2, NULL); 899 | pthread_cond_init(&wait_full_buffer2, NULL); 900 | 901 | for(i = 0;i < 3;i++) 902 | pthread_join(tids[i],NULL); 903 | pthread_mutex_destroy(&mutex1); 904 | pthread_mutex_destroy(&mutex2); 905 | 906 | 907 | return 0; 908 | } 909 | ``` 910 | 911 | #### 3.4.2 pc2 实验结果 912 | 913 | ![pc1.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d12dae722aa3.png) 914 | 915 | #### 3.4.3 pc2 实验思路 916 | 917 | ##### 实验思路 918 | 919 | (1) 定义两个容量为 4 的 buffer:buffer1 与 buffer2。计算者从 buffer1 取出字符,将小写字符转换为大写字符,放入到 buffer2。消费者从 buffer2 取出字符,将其打印到屏幕上。定义互斥信号量用于进程间互斥,定义条件变量用于进程间同步 920 | 921 | ``` 922 | #define CAPACITY 4 //缓冲区的大小 923 | #define ITEM_COUNT 8 //字符的数量 924 | char buffer1[CAPACITY]; 925 | char buffer2[CAPACITY]; 926 | int in1,out1; //定义当前buffer1的读指针和写指针 927 | int in2,out2; //定义当前buffer2的读指针和写指针 928 | pthread_mutex_t mutex1,mutex2; //定义互斥信号量 929 | pthread_cond_t wait_empty_buffer1; 930 | pthread_cond_t wait_full_buffer1; //定义条件变量用于produce与compute之间的同步 931 | pthread_cond_t wait_empty_buffer2; 932 | pthread_cond_t wait_full_buffer2; //定义条件变量用于compute与consume之间的同步 933 | ``` 934 | 935 | (2) produce 程序作为 buffer1 的生产者,在操作之前给 buffer1 加锁并将数据存入。 936 | 937 | ``` 938 | void *produce(void *arg){ 939 | int i; 940 | char item; 941 | 942 | for(i = 0;i < ITEM_COUNT;i++){ 943 | pthread_mutex_lock(&mutex); //对互斥锁进行加锁 944 | while(buffer_is_full(1)) 945 | pthread_cond_wait(&wait_empty_buffer1, &mutex); //P操作:若buffer1满了就等待其为空 946 | item = 'a' + i; 947 | put_item(item,1); 948 | printf("produce item:%c\n",item); 949 | 950 | pthread_cond_signal(&wait_full_buffer1); //V操作:将buffer1的数据缓冲区数目(wait_full_buffer1) + 1 951 | pthread_mutex_unlock(&mutex); //释放信号量 952 | } 953 | return NULL; 954 | } 955 | ``` 956 | 957 | (3) compute 程序先作为 buffer1 的消费者,给 buffer1 加锁并取数;计算者将小写字母变成大写字母;计最后再作为 buffer2 的生产者,给 buffer2 加锁并存数。 958 | 959 | ``` 960 | void *compute(void *arg){ 961 | int i; 962 | char item; 963 | 964 | for(i = 0;i < ITEM_COUNT;i++){ 965 | pthread_mutex_lock(&mutex1); //对信号量1加锁 966 | while(buffer_is_empty(1)) 967 | pthread_cond_wait(&wait_full_buffer1, &mutex1); //P操作:若buffer1为空则持续等待 968 | item = get_item(1); 969 | //printf(" compute get item:%c\n",item); 970 | pthread_cond_signal(&wait_empty_buffer1); //V操作:将buffer1的数据缓冲区数目(wait_empty_buffer1)-1 971 | pthread_mutex_unlock(&mutex1); //释放信号量1 972 | 973 | item -= 32; 974 | 975 | pthread_mutex_lock(&mutex2); //对信号量2加锁 976 | while(buffer_is_full(2)) 977 | pthread_cond_wait(&wait_empty_buffer2, &mutex2);//P操作:若buffer2满了则持续等待 978 | put_item(item,2); 979 | printf(" compute put item:%c\n", item); 980 | pthread_cond_signal(&wait_full_buffer2); //V操作:将buffer2的数据缓冲区数目(wait_full_buffer2)+1 981 | pthread_mutex_unlock(&mutex2); //释放信号量2 982 | } 983 | return NULL; 984 | } 985 | ``` 986 | 987 | (4)消费者作为 buffer2 的消费者,给 buffer2 加锁并取数字。 988 | 989 | ``` 990 | void *consume(void *arg){ 991 | int i; 992 | char item; 993 | for(i = 0;i < ITEM_COUNT;i++){ 994 | pthread_mutex_lock(&mutex2); //对信号量2加锁 995 | while(buffer_is_empty(2)) 996 | pthread_cond_wait(&wait_full_buffer2, &mutex2); //P操作:若buffer2为空则持续等待 997 | item = get_item(2); 998 | printf(" comsume item:%c\n", item); 999 | pthread_cond_signal(&wait_empty_buffer2); //V操作:将buffer2的数据缓冲区数目(wait_empty_buffer2)-1 1000 | pthread_mutex_unlock(&mutex2); //释放信号量2 1001 | } 1002 | return NULL; 1003 | } 1004 | ``` 1005 | 1006 | (5)在主函数中创建三个线程分别用于承担生产者,计算者与消费者。对线程进行初始化,并且定义两个锁用于线程间互斥,再定义四个信号量用于线程间同步,再将三个进程都调用 pthread_join()函数等待线程结束,最终对互斥锁进行注销。 1007 | 1008 | ``` 1009 | int main(){ 1010 | int i; 1011 | in1 = 0; 1012 | in2 = 0; 1013 | out1 = 0; 1014 | out2 = 0; 1015 | pthread_t tids[3]; 1016 | pthread_create(&tids[0],NULL,produce,NULL); 1017 | pthread_create(&tids[1],NULL,compute,NULL); 1018 | pthread_create(&tids[2],NULL,consume,NULL); 1019 | 1020 | pthread_mutex_init(&mutex1, NULL); 1021 | pthread_mutex_init(&mutex2, NULL); 1022 | pthread_cond_init(&wait_empty_buffer1, NULL); 1023 | pthread_cond_init(&wait_full_buffer1, NULL); 1024 | pthread_cond_init(&wait_empty_buffer2, NULL); 1025 | pthread_cond_init(&wait_full_buffer2, NULL); 1026 | 1027 | for(i = 0;i < 3;i++) 1028 | pthread_join(tids[i],NULL); 1029 | pthread_mutex_destroy(&mutex1); 1030 | pthread_mutex_destroy(&mutex2); 1031 | 1032 | return 0; 1033 | } 1034 | ``` 1035 | 1036 | ### 6 pc2.c: 使用信号量解决生产者、计算者、消费者问题 -- 多进程 + 信号量、条件变量 1037 | 1038 | - 功能和前面的实验相同,使用信号量解决 1039 | 1040 | #### 3.5.1 pc2 实验代码 1041 | 1042 | ``` 1043 | #include 1044 | #include 1045 | #include 1046 | #include 1047 | #define CAPACITY 4 1048 | 1049 | char buffer1[CAPACITY]; 1050 | char buffer2[CAPACITY]; 1051 | int in1,out1; 1052 | int in2,out2; 1053 | 1054 | int buffer_is_empty(int index){ 1055 | if(index == 1) 1056 | return in1 == out1; 1057 | if(index == 2) 1058 | return in2 == out2; 1059 | else 1060 | printf("Don`t exist this buffer!,Empty"); 1061 | } 1062 | 1063 | int buffer_is_full(int index){ 1064 | if(index == 1) 1065 | return (in1 + 1) % CAPACITY == out1; 1066 | if(index == 2) 1067 | return (in2 + 1) % CAPACITY == out2; 1068 | else 1069 | printf("Don`t exist this buffer!,Full"); 1070 | } 1071 | char get_item(int index){ 1072 | char item; 1073 | if(index == 1){ 1074 | item = buffer1[out1]; 1075 | out1 = (out1 + 1) % CAPACITY; 1076 | } 1077 | if(index == 2){ 1078 | item = buffer2[out2]; 1079 | out2 = (out2 + 1) % CAPACITY; 1080 | } 1081 | //else 1082 | // printf("Don`t exist this buffer!,Get%d\n",index); 1083 | return item; 1084 | } 1085 | 1086 | void put_item(char item, int index){ 1087 | if(index == 1){ 1088 | buffer1[in1] = item; 1089 | in1 = (in1 + 1) % CAPACITY; 1090 | } 1091 | if(index == 2){ 1092 | buffer2[in2] = item; 1093 | in2 = (in2 + 1) % CAPACITY; 1094 | } 1095 | //else 1096 | // printf("Don`t exist this buffer!Put%c %d\n",item,index); 1097 | } 1098 | 1099 | typedef struct{ 1100 | int value; 1101 | pthread_mutex_t mutex; 1102 | pthread_cond_t cond; 1103 | }sema_t; 1104 | 1105 | void sema_init(sema_t *sema, int value){ 1106 | sema->value = value; 1107 | pthread_mutex_init(&sema->mutex, NULL); 1108 | pthread_cond_init(&sema->cond, NULL); 1109 | } 1110 | 1111 | void sema_wait(sema_t *sema){ 1112 | pthread_mutex_lock(&sema->mutex); 1113 | while(sema->value <= 0) 1114 | pthread_cond_wait(&sema->cond, &sema->mutex); 1115 | sema->value--; 1116 | pthread_mutex_unlock(&sema->mutex); 1117 | } 1118 | 1119 | void sema_signal(sema_t *sema){ 1120 | pthread_mutex_lock(&sema->mutex); 1121 | ++sema->value; 1122 | pthread_cond_signal(&sema->cond); 1123 | pthread_mutex_unlock(&sema->mutex); 1124 | } 1125 | 1126 | sema_t mutex_sema1,mutex_sema2; 1127 | sema_t empty_buffer_sema1; 1128 | sema_t full_buffer_sema1; 1129 | sema_t empty_buffer_sema2; 1130 | sema_t full_buffer_sema2; 1131 | 1132 | volatile int global = 0; 1133 | 1134 | #define ITEM_COUNT 8 1135 | 1136 | void *produce(void *arg){ 1137 | int i; 1138 | char item; 1139 | 1140 | for(i = 0;i < ITEM_COUNT;i++){ 1141 | sema_wait(&empty_buffer_sema1); 1142 | sema_wait(&mutex_sema1); 1143 | 1144 | item = 'a' + i; 1145 | put_item(item,1); 1146 | printf("produce item:%c\n",item); 1147 | 1148 | sema_signal(&mutex_sema1); 1149 | sema_signal(&full_buffer_sema1); 1150 | } 1151 | return NULL; 1152 | } 1153 | void *compute(void *arg){ 1154 | int i; 1155 | char item; 1156 | for(i = 0;i < ITEM_COUNT;i++){ 1157 | sema_wait(&full_buffer_sema1); 1158 | sema_wait(&mutex_sema1); 1159 | 1160 | item = get_item(1); 1161 | // printf(" compute get item:%c\n",item); 1162 | 1163 | sema_signal(&mutex_sema1); 1164 | sema_signal(&empty_buffer_sema1); 1165 | 1166 | item -= 32; 1167 | 1168 | sema_wait(&empty_buffer_sema2); 1169 | sema_wait(&mutex_sema2); 1170 | 1171 | put_item(item,2); 1172 | printf(" compute put item:%c\n", item); 1173 | 1174 | sema_signal(&mutex_sema2); 1175 | sema_signal(&full_buffer_sema2); 1176 | } 1177 | return NULL; 1178 | } 1179 | 1180 | void *consume(void *arg){ 1181 | int i; 1182 | char item; 1183 | for(i = 0;i < ITEM_COUNT;i++){ 1184 | 1185 | sema_wait(&full_buffer_sema2); 1186 | sema_wait(&mutex_sema2); 1187 | 1188 | item = get_item(2); 1189 | printf(" comsume item:%c\n", item); 1190 | 1191 | sema_signal(&mutex_sema2); 1192 | sema_signal(&empty_buffer_sema2); 1193 | } 1194 | return NULL; 1195 | } 1196 | 1197 | int main(){ 1198 | int i; 1199 | in1 = 0; 1200 | in2 = 0; 1201 | out1 = 0; 1202 | out2 = 0; 1203 | pthread_t tids[3]; 1204 | 1205 | sema_init(&mutex_sema1, 1); 1206 | sema_init(&mutex_sema2, 1); 1207 | sema_init(&empty_buffer_sema1,CAPACITY - 1); 1208 | sema_init(&full_buffer_sema1,0); 1209 | sema_init(&empty_buffer_sema2,CAPACITY - 1); 1210 | sema_init(&full_buffer_sema1,0); 1211 | 1212 | 1213 | pthread_create(&tids[0],NULL,produce,NULL); 1214 | pthread_create(&tids[1],NULL,compute,NULL); 1215 | pthread_create(&tids[2],NULL,consume,NULL); 1216 | 1217 | for(i = 0;i < 3;i++) 1218 | pthread_join(tids[i],NULL); 1219 | 1220 | 1221 | return 0; 1222 | } 1223 | ``` 1224 | 1225 | 1226 | #### 3.5.3 pc2 实验思路 1227 | 1228 | (1) 信号量的实现 1229 | 1230 | 此题与上题思路相同,区别在于实现的时候利用信号量。信号量的定义、初始化、wait 和 signal 定义如下,初始化时可以送入信号量的初始个数,wait 一次减少一次信号量个数,signal 一次则增加一次信号量个数。 1231 | 1232 | ``` 1233 | typedef struct{ 1234 | int value; 1235 | pthread_mutex_t mutex; 1236 | pthread_cond_t cond; 1237 | }sema_t; 1238 | 1239 | void sema_init(sema_t *sema, int value){ 1240 | sema->value = value; 1241 | pthread_mutex_init(&sema->mutex, NULL); 1242 | pthread_cond_init(&sema->cond, NULL); 1243 | } 1244 | 1245 | void sema_wait(sema_t *sema){ 1246 | pthread_mutex_lock(&sema->mutex); 1247 | while(sema->value <= 0) 1248 | pthread_cond_wait(&sema->cond, &sema->mutex); 1249 | sema->value--; 1250 | pthread_mutex_unlock(&sema->mutex); 1251 | } 1252 | 1253 | void sema_signal(sema_t *sema){ 1254 | pthread_mutex_lock(&sema->mutex); 1255 | ++sema->value; 1256 | pthread_cond_signal(&sema->cond); 1257 | pthread_mutex_unlock(&sema->mutex); 1258 | } 1259 | ``` 1260 | 1261 | (2)定义信号量并使用 1262 | 1263 | 定义两个信号量 mutex_sema1,mutex_sema2,分别对(生产者-计算者)与(计算者-消费者)进行线程间互斥。此外也定义了四个信号量 1264 | 对共享变量 buffer1,buffer2 进行线程间同步。 1265 | 1266 | 在生产者、计算者、消费者的函数中,先进行 P 操作等待互斥信号量(上锁),再 P 操作获取同步信号量,对 buffer 中的数据进行操作后,V 操作释放互斥信号量及同步信号量(解锁)。这里值得注意的是,需要 P 操作需要先获取同步信号量再对互斥信号量进行上锁,不然可能造饥饿的现象。 1267 | 1268 | ``` 1269 | sema_t mutex_sema1,mutex_sema2; 1270 | sema_t empty_buffer_sema1; 1271 | sema_t full_buffer_sema1; 1272 | sema_t empty_buffer_sema2; 1273 | sema_t full_buffer_sema2; 1274 | void *produce(void *arg){ 1275 | int i; 1276 | char item; 1277 | 1278 | for(i = 0;i < ITEM_COUNT;i++){ 1279 | sema_wait(&empty_buffer_sema1); 1280 | sema_wait(&mutex_sema1); 1281 | 1282 | item = 'a' + i; 1283 | put_item(item,1); 1284 | printf("produce item:%c\n",item); 1285 | 1286 | sema_signal(&mutex_sema1); 1287 | sema_signal(&full_buffer_sema1); 1288 | } 1289 | return NULL; 1290 | } 1291 | void *compute(void *arg){ 1292 | int i; 1293 | char item; 1294 | for(i = 0;i < ITEM_COUNT;i++){ 1295 | sema_wait(&full_buffer_sema1); 1296 | sema_wait(&mutex_sema1); 1297 | 1298 | item = get_item(1); 1299 | // printf(" compute get item:%c\n",item); 1300 | 1301 | sema_signal(&mutex_sema1); 1302 | sema_signal(&empty_buffer_sema1); 1303 | 1304 | item -= 32; 1305 | 1306 | sema_wait(&empty_buffer_sema2); 1307 | sema_wait(&mutex_sema2); 1308 | 1309 | put_item(item,2); 1310 | printf(" compute put item:%c\n", item); 1311 | 1312 | sema_signal(&mutex_sema2); 1313 | sema_signal(&full_buffer_sema2); 1314 | } 1315 | return NULL; 1316 | } 1317 | 1318 | void *consume(void *arg){ 1319 | int i; 1320 | char item; 1321 | for(i = 0;i < ITEM_COUNT;i++){ 1322 | 1323 | sema_wait(&full_buffer_sema2); 1324 | sema_wait(&mutex_sema2); 1325 | 1326 | item = get_item(2); 1327 | printf(" comsume item:%c\n", item); 1328 | 1329 | sema_signal(&mutex_sema2); 1330 | sema_signal(&empty_buffer_sema2); 1331 | } 1332 | return NULL; 1333 | } 1334 | ``` 1335 | 1336 | (3) main 函数中开启三个线程分别对应生产者、计算者、消费者,再对两个互斥信号量以及四个同步信号量进行初始化,调用 pthread_join 函数等待三个进程的结束即可。 1337 | 1338 | ``` 1339 | int main(){ 1340 | int i; 1341 | in1 = 0; 1342 | in2 = 0; 1343 | out1 = 0; 1344 | out2 = 0; 1345 | pthread_t tids[3]; 1346 | 1347 | sema_init(&mutex_sema1, 1); 1348 | sema_init(&mutex_sema2, 1); 1349 | sema_init(&empty_buffer_sema1,CAPACITY - 1); 1350 | sema_init(&full_buffer_sema1,0); 1351 | sema_init(&empty_buffer_sema2,CAPACITY - 1); 1352 | sema_init(&full_buffer_sema1,0); 1353 | 1354 | 1355 | pthread_create(&tids[0],NULL,produce,NULL); 1356 | pthread_create(&tids[1],NULL,compute,NULL); 1357 | pthread_create(&tids[2],NULL,consume,NULL); 1358 | 1359 | for(i = 0;i < 3;i++) 1360 | pthread_join(tids[i],NULL); 1361 | 1362 | 1363 | return 0; 1364 | } 1365 | 1366 | ``` -------------------------------------------------------------------------------- /OS-Experiment/OS实验报告-Muyun99.md: -------------------------------------------------------------------------------- 1 | # 操作系统实验报告 2 | 3 | # 1. 文件读写编程题目 4 | 5 | ### 1.1 myecho.c 6 | 7 | - myecho.c 的功能与系统 echo 程序相同 8 | - 接受命令行参数,并将参数打印出来,例子如下: 9 | 10 | ``` 11 | $ ./myecho x 12 | x 13 | $ ./myecho a b c 14 | a b c 15 | ``` 16 | 17 | #### 1.1.1 myecho 实验代码 18 | 19 | ``` 20 | #include 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | int i = 0; 25 | for(i = 1; i < argc; i++) 26 | printf("%s ",argv[i]); 27 | printf("\n"); 28 | return 0; 29 | } 30 | ``` 31 | 32 | #### 1.1.2 myecho 实验结果 33 | 34 | ![myecho.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/25/5d1230a55ff6e.png) 35 | 36 | #### 1.1.3 myecho 实验思路 37 | 38 | 1.实验预备知识 39 | 40 | (1) main 函数的参数有 argc 和 argv 两个参数 41 | 42 | (2) int argc(arguments count) 43 | argc 表示运行程序传送给 main 函数的命令行参数总个数,包括可执行程序名,其中当 argc=1 时表示只有一个程序名称,此时存储在 argv[0]中 44 | 45 | (3) char \*argv[](arguments value/vecotr) 46 | argv 是一个字符串数组,用来存放指向字符串参数的指针数组,每个元素只想一个参数,空格分割参数,其长度为 argc。数组下标从 0 开始,argv[argc] = NULL。 47 | 48 | 2.实验思路 49 | 使用 main 函数的 argv 与 argc 传递参数,命令行输入的字符串会被分割为字符串数组。用 argc 作为循环变量,输出 argv 字符串数组中的值,注意用空格分隔即可。需要注意的是:argv[0]中存储的是程序名称,这里不应该被输出,所以下标应从 1 开始。 50 | 51 | ### 1.2 mycat.c 52 | 53 | - mycat.c 的功能与系统 cat 程序相同 54 | - mycat 将指定的文件内容输出到屏幕,例子如下: 55 | - 要求使用系统调用 open/read/write/close 实现 56 | 57 | ``` 58 | $ cat /etc/passwd 59 | root:x:0:0:root:/root:/bin/bash 60 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 61 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 62 | ... 63 | $ ./mycat /etc/passwd 64 | root:x:0:0:root:/root:/bin/bash 65 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 66 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 67 | ... 68 | ``` 69 | 70 | #### 1.2.1 mycat 实验代码 71 | 72 | ``` 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | 79 | int main(int argc, char *argv[]) 80 | { 81 | int fd; 82 | char c[1]; 83 | if(argc == 1) 84 | { 85 | while(read(0,c,1)) 86 | write(1,c,1); 87 | } 88 | else 89 | { 90 | int i = 0; 91 | for(i = 1;i < argc;i++) 92 | { 93 | fd = open(argv[i], O_RDONLY); 94 | if(fd == -1) //file open error,output error message 95 | { 96 | printf("mycat: %s:No such file or directory\n", argv[i]); 97 | continue; 98 | } 99 | while(read(fd,c,1)) 100 | write(1,c,1); 101 | close(fd); 102 | } 103 | } 104 | return 0; 105 | } 106 | 107 | ``` 108 | 109 | #### 1.2.2 mycat 实验结果 110 | 111 | ![mycat.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/25/5d123f0e6bd4f.png) 112 | 113 | #### 1.2.3 mycat 实验思路 114 | 115 | 1.cat 命令后可不接参数 116 | 117 | 基于此想法,当命令后参数数量为 0(即 argc 为 1 时),我们将接收到的字符串进行原样不动的输出。 118 | 119 | read(0,c,1)表示从标准输入中读取字符数组 120 | 121 | write(1,c,1)表示将读取的字符数组写到标准输出中去 122 | 123 | 2.cat 命令后可接多个参数 124 | 125 | 基于此想法,当命令后参数数量不为 0 是(即 argc>1 时),我们对 argv 中的文件名进行逐个访问并打开,最后调用 read 与 write 函数将当前文件的字符写到标准输出中去。值得注意的是,如果文件夹名字不合法(即 open 函数返回为-1),则应输出报错信息。 126 | 127 | ### 1.3 mycp.c 128 | 129 | - mycp.c 的功能与系统 cp 程序相同 130 | - 将源文件复制到目标文件,例子如下: 131 | - 要求使用系统调用 open/read/write/close 实现 132 | 133 | ``` 134 | $ cat /etc/passwd 135 | root:x:0:0:root:/root:/bin/bash 136 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 137 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 138 | ... 139 | $ ./mycp /etc/passwd passwd.bak 140 | $ cat passwd.bak 141 | root:x:0:0:root:/root:/bin/bash 142 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 143 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 144 | ... 145 | ``` 146 | 147 | #### 1.3.1 mycp 实验代码 148 | 149 | ``` 150 | #include 151 | #include 152 | #include 153 | #include 154 | #include 155 | #include 156 | #include 157 | 158 | int main(int argc, char *argv[]) 159 | { 160 | if(argc != 3) 161 | { 162 | printf("please check your format, the right format:cp file_src file_target\n"); 163 | exit(0); 164 | } 165 | 166 | char *sourcePath = argv[1]; 167 | char *targetPath = argv[2]; 168 | 169 | int fd1 = open(sourcePath, O_RDONLY); 170 | int fd2 = open(targetPath, O_WRONLY | O_CREAT | O_TRUNC, 0644); 171 | 172 | if(fd1 == -1) 173 | { 174 | printf("open %s error!",sourcePath); 175 | exit(0); 176 | } 177 | if(fd2 == -1) 178 | { 179 | printf("open %s error!",targetPath); 180 | exit(0); 181 | } 182 | char buf[1]; 183 | int count; 184 | 185 | while (read(fd1, buf,1)) 186 | { 187 | write(fd2, buf, 1); 188 | } 189 | close(fd1); 190 | close(fd2); 191 | return 0; 192 | } 193 | 194 | ``` 195 | 196 | #### 1.3.2 mycp 实验结果 197 | 198 | ![mycp.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d12482f41037.png) 199 | 200 | #### 1.3.3 mycp 实验思路 201 | 202 | 1.首先对命令格式与文件是否正常打开进行判断 203 | 204 | 当命令后跟的参数数量少于 3 个时候,提醒用户输入格式错误,并退出当前程序。当文件打开错误时,也提醒用户打开文件失败,并退出当前程序。这里需要注意的点是,在打开目标文件时,若目标文件不存在应该创建一个新文件(O_CREAT),并且为了能够后续操作,将其权限赋为默认权限:664 权限。 205 | 206 | 2.进行复制 207 | 208 | 当文件都正常打开时,按照以往的方法进行复制。调用 read 函数对源文件逐个读取,当其返回的字符个数为 1 时,调用 write 函数写入目标文件中。 209 | 210 | # 2. 多进程题目 211 | 212 | ### 2.1 mysys.c: 实现函数 mysys,用于执行一个系统命令,要求如下 213 | 214 | - mysys 的功能与系统函数 system 相同,要求用进程管理相关系统调用自己实现一遍 215 | - 使用 fork/exec/wait 系统调用实现 mysys 216 | - 不能通过调用系统函数 system 实现 mysys 217 | - 测试程序 218 | 219 | ``` 220 | #include 221 | 222 | void mysys(char *command) 223 | { 224 | 实现该函数,该函数执行一条命令,并等待该命令执行结束 225 | } 226 | 227 | int main() 228 | { 229 | printf("--------------------------------------------------\n"); 230 | mysys("echo HELLO WORLD"); 231 | printf("--------------------------------------------------\n"); 232 | mysys("ls /"); 233 | printf("--------------------------------------------------\n"); 234 | return 0; 235 | } 236 | ``` 237 | 238 | - 测试程序的输出结果 239 | 240 | ``` 241 | -------------------------------------------------- 242 | HELLO WORLD 243 | -------------------------------------------------- 244 | bin core home lib mnt root snap tmp vmlinuz 245 | boot dev initrd.img lost+found opt run srv usr vmlinuz.old 246 | cdrom etc initrd.img.old media proc sbin sys var 247 | -------------------------------------------------- 248 | ``` 249 | 250 | #### 2.1.1 mysys 实验代码 251 | 252 | ``` 253 | #include 254 | #include 255 | #include 256 | #include 257 | #include 258 | 259 | int mysys(char *command) 260 | { 261 | if(command[0] == '\0') 262 | { 263 | printf("command not found!\n"); 264 | return 127; // "command not found!" 265 | } 266 | int pid; 267 | pid = fork(); 268 | if(pid == 0) 269 | { 270 | char *argv[100]; 271 | char *token; 272 | char cmd[sizeof(command) + 1]; 273 | strcpy(cmd, command); 274 | 275 | //get first substr 276 | token = strtok(cmd, " "); 277 | int count = 0; 278 | while(token != NULL) 279 | { 280 | argv[count++] = token; 281 | token = strtok(NULL," "); 282 | } 283 | argv[count] = 0; 284 | if(execvp(argv[0],argv) == -1) 285 | printf("exec failed: %d\n",errno); 286 | } 287 | else 288 | wait(NULL); 289 | } 290 | 291 | int main() 292 | { 293 | mysys(""); 294 | printf("-------------------------------------------\n"); 295 | mysys("pwd"); 296 | 297 | printf("-------------------------------------------\n"); 298 | mysys("ls"); 299 | 300 | printf("-------------------------------------------\n"); 301 | mysys("echo HELLO WORLD"); 302 | 303 | printf("-------------------------------------------\n"); 304 | mysys("ls /"); 305 | 306 | printf("-------------------------------------------\n"); 307 | return 0; 308 | } 309 | ``` 310 | 311 | #### 2.1.2 mysys 实验结果 312 | 313 | ![mysys.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d12546b0072e.png) 314 | 315 | #### 2.1.3 mysys 实验思路 316 | 317 | 1.先验知识 318 | 319 | (1) execvp 函数 320 | 321 | int execvp(const char _file, char _ const argv []); 322 | 323 | execvp()会从 PATH 环境变量所指的目录中查找符合参数 file 的文件名, 找到后便执行该文件, 然后将第二个参数 argv 传给该欲执行的文件 324 | 325 | (2) strtok 函数 326 | 327 | char *strtok(char *str, const char \*delim) 328 | 329 | str -- 要被分解成一组小字符串的字符串 330 | 331 | delim -- 包含分隔符的 C 字符串。 332 | 333 | 该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。 334 | 335 | (3) fork 函数 336 | 337 | pid_t fork(void); 338 | 339 | pid 是进程 ID 的缩写,pid_t 是使用 typedef 定义的进程 ID 类型 340 | 341 | 父进程从 fork 返回处继续执行,在父进程中,fork 返回子进程 PID 342 | 343 | 子进程从 fork 返回处开始执行,在子进程中,fork 返回 0 344 | 345 | 2.实验思路 346 | 347 | (1) 首先判断命令是否合法,经过对传入的命令字符数组的首个字符串进行判断,若不存在则打印错误信息并 return 127(返回 127 是指 command not found!) 348 | 349 | (2) 然后进行 fork 产生子进程,在子进程中完成对 execvp 函数的调用,其中若(pid==0)表达式为真,即当前进程为子进程。 350 | 351 | (3) 在子进程中对传入的字符串进行分割,这里用到了 strtok 函数对空格进行分割,将其分割后的子字符串存入 argv 字符数组中,然后调用 execvp 函数,传入命令及 argv 字符串进行系统调用。 352 | 353 | (4) 父进程中等待子进程完成后退出 mysys 函数。 354 | 355 | ### 2.2 sh1.c 356 | 357 | - 该程序读取用户输入的命令,调用函数 mysys(上一个作业)执行用户的命令,示例如下 358 | 359 | ``` 360 | # 编译sh1.c 361 | $ cc -o sh1 sh1.c 362 | 363 | # 执行sh1 364 | $ ./sh 365 | 366 | # sh1打印提示符>,同时读取用户输入的命令echo,并执行输出结果 367 | > echo a b c 368 | a b c 369 | 370 | # sh1打印提示符>,同时读取用户输入的命令cat,并执行输出结果 371 | > cat /etc/passwd 372 | root:x:0:0:root:/root:/bin/bash 373 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 374 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 375 | ``` 376 | 377 | - 请考虑如何实现内置命令 cd、pwd、exit 378 | 379 | #### 2.2.1 sh1 实验代码 380 | 381 | ``` 382 | #include 383 | #include 384 | #include 385 | #include 386 | #include 387 | #include 388 | #include 389 | char *home; 390 | char *dir; 391 | int mysys(char *command) 392 | { 393 | if(command[0] == '\0') 394 | { 395 | printf("command not found!\n"); 396 | return 127; //"command not found!" 397 | } 398 | int pid; 399 | pid = fork(); 400 | if(pid == 0) 401 | { 402 | char *argv[100]; 403 | char *token; 404 | char cmd[sizeof(command) + 1]; 405 | strcpy(cmd, command); 406 | 407 | //get first substr 408 | token = strtok(cmd, " "); 409 | int count = 0; 410 | while(token != NULL) 411 | { 412 | argv[count++] = token; 413 | token = strtok(NULL," "); 414 | } 415 | argv[count] = 0; 416 | if(execvp(argv[0],argv) == -1) 417 | printf("exec failed: %d\n",errno); 418 | } 419 | else 420 | wait(NULL); 421 | 422 | } 423 | 424 | int choose_fun(char *cmd) 425 | { 426 | char argv[100]; 427 | strcpy(argv,cmd); 428 | 429 | if(argv[0] == '\0') 430 | return 0; 431 | char *token = strtok(argv, " "); 432 | 433 | if(strcmp(token,"cd") == 0) 434 | return 1; 435 | else if(strcmp(token,"exit") == 0) 436 | return 2; 437 | else 438 | return 0; 439 | } 440 | 441 | int main() 442 | { 443 | home = getenv("HOME"); 444 | char buff[100]; 445 | while(1) 446 | { 447 | dir = getcwd(NULL,0); 448 | printf("[%s]> ",dir); 449 | gets(buff); 450 | 451 | int cmdStatus = choose_fun(buff); 452 | 453 | if(cmdStatus == 0) 454 | mysys(buff); 455 | else if(cmdStatus == 1) 456 | { 457 | char targetdir[256]; 458 | sscanf(buff,"cd %s",targetdir); 459 | chdir(targetdir); 460 | } 461 | else if(cmdStatus == 2) 462 | exit(0); 463 | } 464 | } 465 | 466 | ``` 467 | 468 | #### 2.2.2 sh1 实验结果 469 | 470 | ![sh1.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d12fb7ab037c.png) 471 | ![sh1-2.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d12fbdb5e288.png) 472 | 473 | 如上图所示,我实现了 ls 等基础命令的同时,也实现了 cd、pwd、exit 等内置命令。 474 | 475 | #### 2.2.3 sh1 实验思路 476 | 477 | 1.先验知识 478 | 479 | sscanf() 480 | 481 | 函数原型:int sscanf(const char _**restrict** \_Src, const char _**restrict** \_Format, ...) 482 | 483 | 函数功能:从一个字符串中读进与指定格式相符的数据的函数。sscanf 与 scanf 类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。 484 | 485 | 函数示例:sscanf(buff,"cd %s",targetdir); 486 | 487 | 2.实验思路 488 | 489 | (1) 先判断其是否为内置指令 cd 以及 exit。调用 strtok 函数获得指令的一个命令字,若是 cd 命令则返回 1,若是 exit 指令则返回 2,若都不是则返回 3 490 | 491 | ``` 492 | int choose_fun(char *cmd) 493 | { 494 | char argv[100]; 495 | strcpy(argv,cmd); 496 | 497 | if(argv[0] == '\0') 498 | return 0; 499 | char *token = strtok(argv, " "); 500 | 501 | if(strcmp(token,"cd") == 0) 502 | return 1; 503 | else if(strcmp(token,"exit") == 0) 504 | return 2; 505 | else 506 | return 0; 507 | } 508 | ``` 509 | 510 | (2) main 函数中对 choose_fun 返回的状态进行判断,若是普通指令则调用 mysys 函数执行,若是 cd 指令调用 sscanf 指令对指令字符串进行解析得到 targetdir 然后改变路径至 targetdir 511 | 512 | ``` 513 | int main() 514 | { 515 | home = getenv("HOME"); 516 | char buff[100]; 517 | while(1) 518 | { 519 | dir = getcwd(NULL,0); 520 | printf("[%s]> ",dir); 521 | gets(buff); 522 | 523 | int cmdStatus = choose_fun(buff); 524 | 525 | if(cmdStatus == 0) 526 | mysys(buff); 527 | else if(cmdStatus == 1) 528 | { 529 | char targetdir[256]; 530 | sscanf(buff,"cd %s",targetdir); 531 | chdir(targetdir); 532 | } 533 | else if(cmdStatus == 2) 534 | exit(0); 535 | } 536 | } 537 | ``` 538 | 539 | ### 2.3 sh2.c: 实现 shell 程序,要求在第 1 版的基础上,添加如下功能 540 | 541 | - 实现文件重定向 542 | 543 | ``` 544 | # 执行sh2 545 | $ ./sh2 546 | 547 | # 执行命令echo,并将输出保存到文件log中 548 | > echo hello >log 549 | 550 | # 打印cat命令的输出结果 551 | > cat log 552 | hello 553 | ``` 554 | 555 | #### 2.3.1 sh2 实验代码 556 | ``` 557 | #include 558 | #include 559 | #include 560 | #include 561 | #include 562 | #include 563 | #include 564 | #include 565 | #include 566 | char *home; 567 | char *dir; 568 | int std_in; 569 | int std_out; 570 | int mysys(char *command) 571 | { 572 | int status = -1; 573 | if(command[0] == '\0') 574 | { 575 | printf("command not found!\n"); 576 | return 127; //"command not found!" 577 | } 578 | pid_t pid; 579 | pid = fork(); 580 | if(pid == 0) 581 | { 582 | char *argv[100]; 583 | char *token; 584 | char cmd[sizeof(command) + 1]; 585 | strcpy(cmd, command); 586 | 587 | //get first substr 588 | token = strtok(cmd, " "); 589 | int count = 0; 590 | while(token != NULL) 591 | { 592 | argv[count++] = token; 593 | token = strtok(NULL," "); 594 | } 595 | argv[count] = 0; 596 | if(execvp(argv[0],argv)==-1) 597 | { 598 | printf("exec failed: "); 599 | printf("%d\n",errno); 600 | } 601 | else 602 | status = 1; 603 | } 604 | else 605 | while(waitpid(pid,NULL,0) < 0) 606 | { 607 | if(errno!=EINTR) 608 | status = -1; 609 | break; 610 | } 611 | 612 | dup2(std_in,0); 613 | dup2(std_out,1); 614 | return status; 615 | } 616 | int choose_fun(char *cmd) 617 | { 618 | char argv[100]; 619 | strcpy(argv,cmd); 620 | 621 | if(argv[0] == '\0') 622 | return 0; 623 | char *token = strtok(argv, " "); 624 | 625 | if(strcmp(token,"cd") == 0) 626 | return 1; 627 | else if(strcmp(token,"exit") == 0) 628 | return 2; 629 | else 630 | return 0; 631 | } 632 | 633 | int loop() 634 | { 635 | printf("debug1"); 636 | char buff[100]; 637 | char tempstr[100]; 638 | home = getenv("HOME"); 639 | dir = getcwd(NULL,0); 640 | printf("[%s]> ",dir); 641 | gets(buff); 642 | 643 | char *a = NULL; 644 | char *b = NULL; 645 | a = strchr(buff, '<'); 646 | b = strchr(buff, '>'); 647 | 648 | int inindex = 0; 649 | int outindex = 0; 650 | int count = 0; 651 | 652 | char *argv[100]; 653 | char *token; 654 | char cmd[sizeof(buff) + 1]; 655 | strcpy(cmd, buff); 656 | token = strtok(cmd,""); 657 | while(token != NULL) 658 | { 659 | if(strchr(token,'<')) 660 | inindex = count+1; 661 | else if(strchr(token,'>')) 662 | outindex = count+1; 663 | argv[count++] = token; 664 | token = strtok(cmd," "); 665 | } 666 | 667 | if(a != NULL && b != NULL) 668 | { 669 | char *in = argv[inindex]; 670 | char *out = argv[outindex]; 671 | int fdin,fdout; 672 | fdin = open(in,O_RDWR,0666); 673 | fdout = open(out,O_CREAT|O_RDWR,0666); 674 | if(fdin == -1) 675 | { 676 | printf("File %s open failed!\n",in); 677 | return -1; 678 | } 679 | if(fdout == -1) 680 | { 681 | printf("File %s open failed!\n",out); 682 | return -1; 683 | } 684 | dup2(fdin,0); 685 | dup2(fdout,1); 686 | close(fdin); 687 | close(fdout); 688 | return mysys(buff); 689 | } 690 | else if(a != NULL) 691 | { 692 | char *in = argv[inindex]; 693 | int fdin = open(in, O_RDWR, 0666); 694 | dup2(fdin,0); 695 | close(fdin); 696 | return mysys(buff); 697 | } 698 | else if(b != NULL) 699 | { 700 | char *out = argv[outindex]; 701 | int fdout = open(out, O_CREAT|O_RDWR, 0666); 702 | dup2(fdout,1); 703 | close(fdout); 704 | return mysys(buff); 705 | } 706 | else 707 | { 708 | printf("debug1"); 709 | int cmdStatus = choose_fun(buff); 710 | if(cmdStatus == 0) 711 | mysys(buff); 712 | else if(cmdStatus == 1) 713 | { 714 | char targetdir[256]; 715 | sscanf(buff,"cd %s",targetdir); 716 | chdir(targetdir); 717 | } 718 | else if(cmdStatus == 2) 719 | exit(0); 720 | } 721 | } 722 | int main() 723 | { 724 | std_in = dup(0); 725 | std_out = dup(1); 726 | while(1) 727 | { 728 | loop(); 729 | } 730 | return 0; 731 | } 732 | 733 | ``` 734 | 735 | #### 2.3.2 sh2 实验结果 736 | 737 | #### 2.3.3 sh2 实验思路 738 | 739 | 1.先验知识 740 | 741 | (1) strchr() 742 | 743 | 函数原型:extern char *strchr(const char *s,char c) 744 | 745 | 函数功能:可以查找字符串 s 中首次出现字符 c 的位置 746 | 747 | 函数示例: 748 | 749 | (2) dup2() 750 | 751 | 函数原型:int dup2(int oldfd, int newfd); 752 | 753 | 函数功能:dup2 可以用 newfd 参数指定新描述符的数值,如果 newfd 已经打开,则先将其关闭。如果 newfd 等于 oldfd,则 dup2 返回 newfd, 而不关闭它。dup2 函数返回的新文件描述符同样与参数 oldfd 共享同一文件表项。 754 | 755 | 函数示例: 756 | 757 | ``` 758 | std_in = dup(0); 759 | dup2(std_in,0); 760 | ``` 761 | 762 | 2.实验思路 763 | 764 | (1) 查看有无需要重定向的部分,定义a,b指针,调用strchr()函数扫描是否有'<'以及'>'字符。并且将指令按照空格解析出argv数组,并记录下'<'与'>'出现的位置,这样能够找到需要重定向的文件名了。扫描结果分别对应四个如下。 765 | 766 | 扫描结果 | 解释 | 对应入口 767 | --|--|-- 768 | 当a,b都不为空时 | 既有输出重定向,又有输入重定向 | 重定向输入与输出后判断调用mysys 769 | 当a为空,b不为空时 | 只有输出重定向,没有输入重定向 | 重定向输出后调用mysys 770 | 当b为空,a不为空时 | 没有输出重定向,只有输入重定向 | 重定向输入后调用mysys 771 | 当a,b都为空时 | 没有输入和输出重定向 | 直接调用mysys 772 | ``` 773 | char *a = NULL; 774 | char *b = NULL; 775 | a = strchr(buff, '<'); 776 | b = strchr(buff, '>'); 777 | if(a != NULL && b != NULL){} 778 | else if(a != NULL) {} 779 | else if(b != NULL) {} 780 | else {} 781 | ``` 782 | (2) 在重定向时用到了dup2这个命令,我们需要先正确打开对应的文件,然后调用dup2命令进行重定向。由于cd与exit命令无需用到重定向,所以在完成本条指令之后需要在mysys中将重定向后的再重定向回来。 783 | ``` 784 | int mysys(char *command) 785 | { ... 786 | dup2(std_in,0); 787 | dup2(std_out,1); 788 | return status; 789 | } 790 | 791 | if(a != NULL && b != NULL) 792 | { 793 | char *in = argv[inindex]; 794 | char *out = argv[outindex]; 795 | int fdin,fdout; 796 | fdin = open(in,O_RDWR,0666); 797 | fdout = open(out,O_CREAT|O_RDWR,0666); 798 | if(fdin == -1) 799 | { 800 | printf("File %s open failed!\n",in); 801 | return -1; 802 | } 803 | if(fdout == -1) 804 | { 805 | printf("File %s open failed!\n",out); 806 | return -1; 807 | } 808 | dup2(fdin,0); 809 | dup2(fdout,1); 810 | close(fdin); 811 | close(fdout); 812 | return mysys(buff); 813 | } 814 | 815 | ``` 816 | 817 | ### 2.4 sh3.c: 实现 shell 程序,要求在第 2 版的基础上,添加如下功能 818 | 819 | - 实现管道 820 | 821 | ``` 822 | # 执行sh3 823 | $ ./sh3 824 | 825 | # 执行命令cat和wc,使用管道连接cat和wc 826 | > cat /etc/passwd | wc -l 827 | ``` 828 | 829 | - 考虑如何实现管道和文件重定向 830 | 831 | ``` 832 | $ cat input.txt 833 | 3 834 | 2 835 | 1 836 | 3 837 | 2 838 | 1 839 | $ cat output.txt 840 | $ cat output.txt 841 | 1 842 | 2 843 | 3 844 | ``` 845 | 846 | #### 2.4.1 sh3 实验代码 847 | ``` 848 | #include 849 | #include 850 | #include 851 | #include 852 | #include 853 | #include 854 | #include 855 | #include 856 | #include 857 | 858 | #define MAX_BUFFLEN 1024 859 | #define MAX_NUM 100 860 | 861 | char *home; 862 | char *dir; 863 | int recover_in; 864 | int recover_out; 865 | int fdin, fdout; 866 | int fd[2], fd_tmp[2]; 867 | int flag = -1; 868 | 869 | void split(char *src, int *argc, char **argv) 870 | { 871 | char code[MAX_BUFFLEN]; 872 | int count = 0; // N.O. of arguments 873 | char *next = NULL; 874 | char *rest = code; 875 | strcpy(code, src); 876 | argv[count++] = code; 877 | while(next = strchr(rest, ' ')) 878 | { 879 | next[0] = '\0'; 880 | rest = next + 1; 881 | // printf("rest = \"%s\"\n", rest); 882 | 883 | if(rest[0] != '\0' && rest[0] != ' ') 884 | argv[count++] = rest; 885 | if(count + 2 > MAX_NUM) 886 | return ; 887 | } 888 | argv[count++] = NULL; 889 | *argc = count - 1; 890 | } 891 | 892 | int mysys(const char *cmdstring) 893 | { 894 | pid_t pid; 895 | int status = -1; 896 | 897 | if (cmdstring == NULL) 898 | return 1; 899 | 900 | if ((pid = fork()) < 0) 901 | status = -1; 902 | else if (pid == 0) 903 | { 904 | dup2(fdin, 0); 905 | dup2(fdout, 1); 906 | 907 | close(fdin); 908 | close(fdout); 909 | execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); 910 | exit(127); 911 | } 912 | else 913 | { 914 | while (waitpid(pid, &status, 0) < 0) 915 | { 916 | if (errno != EINTR) 917 | { 918 | status = -1; 919 | break; 920 | } 921 | } 922 | } 923 | return status; 924 | } 925 | 926 | int judge_buff(char *buff) 927 | { 928 | //printf("In judge: [%s]\n", buff); 929 | if(buff[0] == '\0') 930 | return 0; 931 | char code[MAX_BUFFLEN]; 932 | strcpy(code, buff); 933 | char *next = strchr(code, ' '); 934 | if(next != NULL) 935 | next[0] = '\0'; 936 | //printf("[code] %s", code); 937 | if(strcmp(code, "cd") == 0) 938 | return 1; 939 | else if(strcmp(code, "exit") == 0) 940 | { 941 | //printf("In judge: [%s]\n", buff); 942 | exit(-1); 943 | 944 | } 945 | else 946 | return 0; 947 | } 948 | 949 | int cd(char *buff) 950 | { 951 | int argc = 0; 952 | char *argv[MAX_NUM]; // no more than 100 arguments 953 | int count = 0; // N.O. of arguments 954 | split(buff, &argc, argv); 955 | count = argc; 956 | 957 | if(count == 1) 958 | { 959 | chdir(home); 960 | dir = getcwd(NULL, 0); 961 | } 962 | else 963 | { 964 | int res = chdir(argv[count - 1]); 965 | dir = getcwd(NULL, 0); 966 | if(res == -1) 967 | { 968 | printf("cd: No such path %s\n", argv[count - 1]); 969 | return -1; 970 | } 971 | } 972 | return 0; 973 | } 974 | 975 | int go(char *buff) 976 | { 977 | int res = judge_buff(buff); 978 | if(res == 0) 979 | mysys(buff); 980 | else if(res == 1) 981 | cd(buff); 982 | else if(res == -1) 983 | return -1; 984 | return 1; 985 | } 986 | 987 | void strip(char *s) 988 | { 989 | size_t i; 990 | size_t len = strlen(s); 991 | size_t offset = 0; 992 | for(i = 0; i < len; ++i){ 993 | char c = s[i]; 994 | if(c==0x0d||c==0x0a) ++offset; 995 | else s[i-offset] = c; 996 | } 997 | s[len-offset] = '\0'; 998 | } 999 | 1000 | void strip_char(char *s, char bad) 1001 | { 1002 | size_t i; 1003 | size_t len = strlen(s); 1004 | size_t offset = 0; 1005 | for(i = 0; i < len; ++i){ 1006 | char c = s[i]; 1007 | if(c==bad) ++offset; 1008 | else s[i-offset] = c; 1009 | } 1010 | s[len-offset] = '\0'; 1011 | } 1012 | 1013 | void strip_dup(char *s) 1014 | { 1015 | size_t i; 1016 | size_t len = strlen(s); 1017 | 1018 | for(i = 0; i < len; ++i) 1019 | { 1020 | char c = s[i]; 1021 | if(c == '<' || c == '>') 1022 | s[i] = '\0'; 1023 | } 1024 | } 1025 | 1026 | void strip_pipe(char *s) 1027 | { 1028 | size_t i; 1029 | size_t len = strlen(s); 1030 | 1031 | for(i = 0; i < len; ++i) 1032 | { 1033 | char c = s[i]; 1034 | if(c == '|') 1035 | s[i] = '\0'; 1036 | } 1037 | } 1038 | 1039 | int go_dup(char *buff) 1040 | { 1041 | char code[MAX_BUFFLEN]; 1042 | strcpy(code, buff); 1043 | 1044 | char *a = NULL; 1045 | char *b = NULL; 1046 | a = strchr(buff, '<'); 1047 | b = strchr(buff, '>'); 1048 | 1049 | strip_dup(code); 1050 | if(a != NULL && b != NULL) 1051 | { 1052 | char *in = a + 1 - buff + code; 1053 | char *out = b + 1 - buff + code; 1054 | strip_char(in, ' '); 1055 | strip_char(out, ' '); 1056 | // printf("[in] %s\n", in); 1057 | // printf("[out]%s\n", out); 1058 | // printf("[code]%s\n", code); 1059 | 1060 | fdin = open(in, O_RDWR, 0666); 1061 | fdout = open(out, O_CREAT|O_RDWR, 0666); 1062 | if(fdin == -1) 1063 | { 1064 | printf("File %s open faild\n", in); 1065 | return -1; 1066 | } 1067 | if(fdout == -1) 1068 | { 1069 | printf("File %s open faild\n", out); 1070 | return -1; 1071 | } 1072 | 1073 | return mysys(code); 1074 | } 1075 | else if(a != NULL) 1076 | { 1077 | char *in = a + 1 - buff + code; 1078 | strip_char(in, ' '); 1079 | 1080 | fdin = open(in, O_RDWR, 0666); 1081 | fdout = recover_out; 1082 | if(fdin == -1) 1083 | { 1084 | printf("File %s open faild\n", in); 1085 | return -1; 1086 | } 1087 | return mysys(code); 1088 | } 1089 | else if(b != NULL) 1090 | { 1091 | char *out = b + 1 - buff + code; 1092 | strip_char(out, ' '); 1093 | 1094 | fdin = recover_in; 1095 | fdout = open(out, O_CREAT|O_RDWR, 0666); 1096 | if(fdout == -1) 1097 | { 1098 | printf("File %s open faild\n", out); 1099 | return -1; 1100 | } 1101 | return mysys(code); 1102 | } 1103 | else 1104 | { 1105 | fdin = recover_in; 1106 | fdout = recover_out; 1107 | return go(buff); 1108 | } 1109 | 1110 | } 1111 | 1112 | int count_pipe(char *buff, int loc[]) 1113 | { 1114 | char *next = buff; 1115 | int count = 0; 1116 | loc[count++] = 0; 1117 | while(next = strchr(next, '|')) 1118 | { 1119 | //printf("[next] %s\n", next); 1120 | next = next + 1; 1121 | loc[count++] = next - buff; 1122 | } 1123 | 1124 | return count; 1125 | } 1126 | 1127 | int pipe_sys(const char *cmdstring) 1128 | { 1129 | pid_t pid; 1130 | 1131 | pid = fork(); 1132 | if (pid == 0) 1133 | { 1134 | if(flag == 0) 1135 | { 1136 | //printf("[flag] %d\t[code] %s\n", flag, cmdstring); 1137 | 1138 | dup2(fd[1], 1); 1139 | close(fd[0]); 1140 | close(fd[1]); 1141 | execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); 1142 | exit(127); 1143 | } 1144 | else if(flag == 1) 1145 | { 1146 | //printf("[flag] %d\t[code] %s\n", flag, cmdstring); 1147 | 1148 | dup2(fd[0], 0); 1149 | close(fd[0]); 1150 | close(fd[1]); 1151 | execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); 1152 | exit(127); 1153 | } 1154 | else if(flag == 2) 1155 | { 1156 | //printf("[flag] %d\t[code] %s\n", flag, cmdstring); 1157 | 1158 | dup2(fd[0], 0); 1159 | close(fd[0]); 1160 | close(fd[1]); 1161 | // 输出进入临时管道 1162 | dup2(fd_tmp[1], 1); 1163 | close(fd_tmp[0]); 1164 | close(fd_tmp[1]); 1165 | execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); 1166 | exit(127); 1167 | } 1168 | } 1169 | wait(NULL); 1170 | //printf("wait once\n"); 1171 | return 0; 1172 | } 1173 | 1174 | int go_pipe(char *buff) 1175 | { 1176 | 1177 | 1178 | int res; 1179 | char code[MAX_BUFFLEN]; 1180 | strcpy(code, buff); 1181 | strip_pipe(code); 1182 | int loc[MAX_NUM]; 1183 | int count = count_pipe(buff, loc); 1184 | //printf("[debug] count: %d\n", count); 1185 | if(count == 1) 1186 | { 1187 | fdin = recover_in; 1188 | fdout = recover_out; 1189 | return go_dup(buff); 1190 | } 1191 | 1192 | for(int i = 0; i < count; i++) 1193 | { 1194 | //printf("[debug] %d pipe: %s\n", i, code+loc[i]); 1195 | if(flag == 2) 1196 | { 1197 | dup2(fd_tmp[0], fd[0]); 1198 | dup2(fd_tmp[1], fd[1]); 1199 | close(fd_tmp[0]); 1200 | close(fd_tmp[1]); 1201 | pipe(fd_tmp); 1202 | close(fd[1]); 1203 | } 1204 | if(flag == 0) 1205 | { 1206 | close(fd[1]); 1207 | } 1208 | if(i == 0) 1209 | { 1210 | flag = 0; 1211 | } 1212 | else if(i == count - 1) 1213 | { 1214 | flag = 1; 1215 | } 1216 | else 1217 | { 1218 | flag = 2; 1219 | } 1220 | res = pipe_sys(code + loc[i]); 1221 | } 1222 | 1223 | // close(fd[0]); 1224 | // close(fd[1]); 1225 | // close(fd_tmp[0]); 1226 | // close(fd_tmp[1]); 1227 | return res; 1228 | } 1229 | 1230 | void find_last_dir(char **now) 1231 | { 1232 | char *next = NULL; 1233 | char *rest = dir; 1234 | //printf("[dir] %s\n", dir); 1235 | while(next = strchr(rest, '/')) 1236 | rest = next + 1; 1237 | if(rest == '\0') 1238 | *now = dir; 1239 | else 1240 | *now = rest; 1241 | } 1242 | 1243 | void print_prefix() 1244 | { 1245 | 1246 | if(strcmp(home, dir) == 0) 1247 | printf("\033[33m%c \033[34;1m~ \033[0m", '>'); 1248 | //printf("[~]$ "); 1249 | else 1250 | { 1251 | char *now = NULL; 1252 | find_last_dir(&now); 1253 | printf("\033[33m%c \033[34;1m%s \033[0m", '>', now); 1254 | //printf("[!]$ "); 1255 | } 1256 | 1257 | } 1258 | 1259 | int main() 1260 | { 1261 | pipe(fd); 1262 | pipe(fd_tmp); 1263 | 1264 | recover_in = dup(0); 1265 | recover_out = dup(1); 1266 | home = getenv("HOME"); 1267 | dir = getcwd(NULL, 0); 1268 | char buff[MAX_BUFFLEN]; 1269 | 1270 | 1271 | print_prefix(); 1272 | while(fgets(buff, sizeof(buff), stdin)) 1273 | { 1274 | strip(buff); 1275 | 1276 | go_pipe(buff); 1277 | 1278 | pipe(fd); 1279 | pipe(fd_tmp); 1280 | print_prefix(); 1281 | } 1282 | 1283 | return 0; 1284 | } 1285 | ``` 1286 | 1287 | #### 2.4.2 sh3 实验思路 1288 | 1.先验知识 1289 | 1290 | (1) 管道 1291 | 1292 | 管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质: 1293 | 1294 | 1. 其本质是一个伪文件(实为内核缓冲区) 1295 | 1296 | 2. 由两个文件描述符引用,一个表示读端,一个表示写端。 1297 | 1298 | 3. 规定数据从管道的写端流入管道,从读端流出。 1299 | 1300 | 管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。 1301 | 1302 | (2) 管道的局限性 1303 | 1304 | 1. 数据自己读不能自己写(其实可以,但没有意义) 1305 | 1306 | 2. 数据一旦被读走,便不在管道中存在,不可反复读取。 1307 | 1308 | 3. 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。 1309 | 1310 | 4. 只能在有公共祖先的进程间使用管道。 1311 | 1312 | 常见的通信方式有,单工通信、半双工通信、全双工通信。 1313 | 1314 | (3) 管道的使用 1315 | 函数名 | 函数原型 | 函数功能 | 函数示例 1316 | --|--|--|-- 1317 | pipe() | int pipe(int pipefd[2]); | 函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd[0] → r; fd[1] → w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。| int fd[2]; pipe(fd); 1318 | write() | int write(int, const void *, unsigned int) | 用于向管道中写数据 | write(fds[1],"hello",5); 1319 | read() | int read(int, void *, unsigned int) | 用于读取管道中的数据 | read(fds[0],buf,10); 1320 | 1321 | (4) 管道用于进程间通信 1322 | 1323 | 1. 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。 1324 | 1325 | 2.父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。 1326 | 1327 | 3.父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。 1328 | 1329 | 2.实验思路 1330 | 1331 | (1) 主函数中仍然使用while循环来实现交互终端,函数loop用于解释执行命令,支持管道与重定向。由于管道是半双工的,定义了两个管道 1332 | 1333 | (2)函数go_pipe中判断字符’|’的个数,若不存在‘|’,则调用sh2.c中的go_dup函数。 1334 | 1335 | (3) 若字符’|’的个数不为0,则在子进程之间使用管道。在计算管道个数时,利用loc数组存下每个管道前后命令的位置,以方便为每个命令调用一个子进程。用一个for循环来创建每一个子进程。标志flag初始值为-1,用于告诉当前子进程,前后管道的数量。处于中间的子进程前面有管道,后面也有管道,令flag=2;第一个子进程只有后面有管道,flag=0,最后一个子进程只有前面有管道,falg=1。 1336 | 1337 | 在进入第二个子进程之前,关闭管道的入口(写端)。 1338 | 1339 | 若前一个子进程用了两个管道,则在进入下一个子进程之前,抛弃老管道fd,将临时管道fd_tmp设置成当前管道fd,并关闭当前管道的入口(写端)。 1340 | 1341 | 调用pipe_sys函数执行子进程。 1342 | 1343 | (4) 子进程中根据flag判断当前命令前后的管道数量,若前面无管道,则将标准输出重定向到管道入口;若后面无管道,则将标准输入重定向到管道出口;若前后均有管道,则将标准输入重定向到当前管道,将标准输出重定向到临时短道。 1344 | 1345 | 1346 | 1347 | # 3. 多线程题目 1348 | 1349 | ### 3.1 pi1.c: 使用 2 个线程根据莱布尼兹级数计算 PI 1350 | 1351 | - 莱布尼兹级数公式: 1 - 1/3 + 1/5 - 1/7 + 1/9 - ... = PI/4 1352 | - 主线程创建 1 个辅助线程 1353 | - 主线程计算级数的前半部分 1354 | - 辅助线程计算级数的后半部分 1355 | - 主线程等待辅助线程运行結束后,将前半部分和后半部分相加 1356 | 1357 | #### 3.1.1 pi1 实验代码 1358 | 1359 | ``` 1360 | #include 1361 | #include 1362 | #include 1363 | 1364 | #define NUMBER 100000 1365 | 1366 | double PI; 1367 | double worker_output; 1368 | double master_output; 1369 | 1370 | void *worker(void *arg){ 1371 | int i; 1372 | worker_output = 0; 1373 | for(i = 1; i <= NUMBER;i++){ 1374 | if(i % 2 == 0) 1375 | worker_output -= 1/(2*(double)i - 1); 1376 | else 1377 | worker_output += 1/(2*(double)i - 1); 1378 | } 1379 | } 1380 | 1381 | void master(){ 1382 | int i; 1383 | master_output = 0; 1384 | for(i = NUMBER + 1;i <= NUMBER*2;i++){ 1385 | if(i % 2 == 0) 1386 | master_output -= 1 / (2 * (double)i - 1); 1387 | else 1388 | master_output += 1 / (2 * (double)i - 1); 1389 | } 1390 | } 1391 | 1392 | int main() 1393 | { 1394 | pthread_t worker_tid; 1395 | pthread_create(&worker_tid, NULL, &worker, NULL); 1396 | master(); 1397 | pthread_join(worker_tid,NULL); 1398 | PI = (worker_output + master_output) * 4; 1399 | printf("PI:%lf\n",PI); 1400 | return 0; 1401 | } 1402 | 1403 | ``` 1404 | 1405 | #### 3.1.2 pi1 实验结果 1406 | 1407 | ![pi1.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d127298c4ae7.png) 1408 | 1409 | #### 3.1.3 pi1 实验思路 1410 | 1411 | (1)使用两个线程计算 PI,主线程计算前半部分,辅助线程计算后半部分。将最后的计算结果相加后乘以 4 得到 PI 的估计值。采用 pthread_create 函数创建辅助线程,使用 pthread_join 函数等待辅助线程结束。 1412 | 1413 | (2)worker 和 master 函数分别计算级数的后半段和前半段,迭代次数 NUMBER 越大,数字越精确。 1414 | 1415 | ### 3.2 pi2.c: 使用 N 个线程根据莱布尼兹级数计算 PI 1416 | 1417 | - 与上一题类似,但本题更加通用化,能适应 N 个核心,需要使用线程参数来实现 1418 | - 主线程创建 N 个辅助线程 1419 | - 每个辅助线程计算一部分任务,并将结果返回 1420 | - 主线程等待 N 个辅助线程运行结束,将所有辅助线程的结果累加 1421 | 1422 | #### 3.2.1 pi2 实验代码 1423 | 1424 | ``` 1425 | #include 1426 | #include 1427 | #include 1428 | #include 1429 | 1430 | #define NUMBER 100000 1431 | #define N 100 1432 | 1433 | double PI; 1434 | struct param{ 1435 | int start; 1436 | int end; 1437 | }; 1438 | 1439 | struct result{ 1440 | double worker_output; 1441 | }; 1442 | 1443 | void *worker(void *arg){ 1444 | int i; 1445 | struct param *param; 1446 | struct result *result; 1447 | double worker_output = 0; 1448 | param = (struct param *) arg; 1449 | 1450 | for(i = param->start; i <= param->end;i++){ 1451 | if(i % 2 == 0) 1452 | worker_output -= 1/(2*(double)i - 1); 1453 | else 1454 | worker_output += 1/(2*(double)i - 1); 1455 | } 1456 | result = malloc(sizeof(struct result)); 1457 | result->worker_output = worker_output; 1458 | printf("worker %d = %.10lf\n",param->start / NUMBER, worker_output); 1459 | return result; 1460 | } 1461 | 1462 | 1463 | int main() 1464 | { 1465 | int i; 1466 | pthread_t worker_tids[N]; 1467 | struct param params[N]; 1468 | PI = 0.0; 1469 | 1470 | for(i = 0; i < N;i++){ 1471 | struct param *param; 1472 | param = ¶ms[i]; 1473 | param->start =i * NUMBER + 1; 1474 | param->end = (i+1) * NUMBER; 1475 | pthread_create(&worker_tids[i], NULL, worker, param); 1476 | } 1477 | 1478 | for(i = 0;i < N;i++){ 1479 | struct result *result; 1480 | pthread_join(worker_tids[i],(void **)&result); 1481 | PI += result->worker_output; 1482 | free(result); 1483 | } 1484 | PI = PI * 4; 1485 | printf("PI:%.10lf\n",PI); 1486 | return 0; 1487 | } 1488 | ``` 1489 | 1490 | #### 3.2.2 pi2 实验结果 1491 | 1492 | ![pi2-2.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d127466c0a48.png) 1493 | ![pi2-1.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d127466c4c6d.png) 1494 | 1495 | #### 3.2.3 pi2 实验思路 1496 | 1497 | (1) 主线程采用 for 循环产生 100 个线程来计算 PI。每个线程计算 1/100 的部分,计算起止点作为 pthread_create 函数的参数 param 传入辅助线程的线程入口函数。在 Worker 函数中,通过 param = (struct param \*) arg 来接收传过来的 param 结构体。 1498 | 1499 | (2) 主线程采用 for 循环,将每个辅助线程的计算结果利用 pthread_join 函数接受线程入口函数的返回值 result,然后获得每一个 worker 的 worker_output 在进行相加得到 PI 的值。 1500 | 1501 | ### 3.3 sort.c: 多线程排序 1502 | 1503 | - 主线程创建一个辅助线程 1504 | - 主线程使用选择排序算法对数组的前半部分排序 1505 | - 辅助线程使用选择排序算法对数组的后半部分排序 1506 | - 主线程等待辅助线程运行結束后,使用归并排序算法归并数组的前半部分和后半部分 1507 | 1508 | #### 3.3.1 sort 实验代码 1509 | ``` 1510 | #include 1511 | #include 1512 | #include 1513 | #include 1514 | 1515 | #define MAX_ARRAY 100 1516 | #define MAX_NUM 10000 1517 | 1518 | void *selectSort(void *argc){ 1519 | int *argv = (int *)argc; 1520 | int i,j,min,record = -1,temp; 1521 | for(i = 0;i < MAX_ARRAY/2; ++i){ 1522 | min = argv[i]; 1523 | for(j = i;j < MAX_ARRAY / 2;++j){ 1524 | if(argv[j] < min){ 1525 | record = j; 1526 | min = argv[j]; 1527 | } 1528 | } 1529 | temp = argv[i]; 1530 | argv[i] = argv[record]; 1531 | argv[record] = temp; 1532 | } 1533 | return NULL; 1534 | } 1535 | 1536 | void Merge(int *arg1, int*arg2){ 1537 | int i = 0; 1538 | int j = 0; 1539 | int k = 0; 1540 | for(j = MAX_ARRAY/2;i < MAX_ARRAY/2 && j < MAX_ARRAY;++k){ 1541 | if(arg1[i] < arg1[j]) 1542 | arg2[k] = arg1[i++]; 1543 | else 1544 | arg2[k] = arg1[j++]; 1545 | } 1546 | while(i < MAX_ARRAY/2) 1547 | arg2[k++] = arg1[i++]; 1548 | while(j < MAX_ARRAY) 1549 | arg2[k++] = arg1[j++]; 1550 | 1551 | } 1552 | void printArray(int *array){ 1553 | int i = 0; 1554 | for(;i 1664 | #include 1665 | #include 1666 | #include 1667 | #define CAPACITY 4 1668 | 1669 | char buffer1[CAPACITY]; 1670 | char buffer2[CAPACITY]; 1671 | int in1,out1; 1672 | int in2,out2; 1673 | 1674 | int buffer_is_empty(int index){ 1675 | if(index == 1) 1676 | return in1 == out1; 1677 | if(index == 2) 1678 | return in2 == out2; 1679 | else 1680 | printf("Don`t exist this buffer!,Empty"); 1681 | } 1682 | 1683 | int buffer_is_full(int index){ 1684 | if(index == 1) 1685 | return (in1 + 1) % CAPACITY == out1; 1686 | if(index == 2) 1687 | return (in2 + 1) % CAPACITY == out2; 1688 | else 1689 | printf("Don`t exist this buffer!,Full"); 1690 | } 1691 | char get_item(int index){ 1692 | char item; 1693 | if(index == 1){ 1694 | item = buffer1[out1]; 1695 | out1 = (out1 + 1) % CAPACITY; 1696 | } 1697 | if(index == 2){ 1698 | item = buffer2[out2]; 1699 | out2 = (out2 + 1) % CAPACITY; 1700 | } 1701 | //else 1702 | // printf("Don`t exist this buffer!,Get%d\n",index); 1703 | return item; 1704 | } 1705 | 1706 | void put_item(char item, int index){ 1707 | if(index == 1){ 1708 | buffer1[in1] = item; 1709 | in1 = (in1 + 1) % CAPACITY; 1710 | } 1711 | if(index == 2){ 1712 | buffer2[in2] = item; 1713 | in2 = (in2 + 1) % CAPACITY; 1714 | } 1715 | //else 1716 | // printf("Don`t exist this buffer!Put%c %d\n",item,index); 1717 | } 1718 | 1719 | pthread_mutex_t mutex1,mutex2; 1720 | pthread_cond_t wait_empty_buffer1; 1721 | pthread_cond_t wait_full_buffer1; 1722 | pthread_cond_t wait_empty_buffer2; 1723 | pthread_cond_t wait_full_buffer2; 1724 | 1725 | 1726 | volatile int global = 0; 1727 | 1728 | #define ITEM_COUNT 8 1729 | 1730 | void *produce(void *arg){ 1731 | int i; 1732 | char item; 1733 | 1734 | for(i = 0;i < ITEM_COUNT;i++){ 1735 | pthread_mutex_lock(&mutex1); 1736 | while(buffer_is_full(1)) 1737 | pthread_cond_wait(&wait_empty_buffer1, &mutex1); 1738 | item = 'a' + i; 1739 | put_item(item,1); 1740 | printf("produce item:%c\n",item); 1741 | 1742 | pthread_cond_signal(&wait_full_buffer1); 1743 | pthread_mutex_unlock(&mutex1); 1744 | } 1745 | return NULL; 1746 | } 1747 | void *compute(void *arg){ 1748 | int i; 1749 | char item; 1750 | for(i = 0;i < ITEM_COUNT;i++){ 1751 | pthread_mutex_lock(&mutex1); 1752 | while(buffer_is_empty(1)) 1753 | pthread_cond_wait(&wait_full_buffer1, &mutex1); 1754 | item = get_item(1); 1755 | //printf(" compute get item:%c\n",item); 1756 | pthread_cond_signal(&wait_empty_buffer1); 1757 | pthread_mutex_unlock(&mutex1); 1758 | 1759 | item -= 32; 1760 | 1761 | pthread_mutex_lock(&mutex2); 1762 | while(buffer_is_full(2)) 1763 | pthread_cond_wait(&wait_empty_buffer2, &mutex2); 1764 | put_item(item,2); 1765 | printf(" compute put item:%c\n", item); 1766 | pthread_cond_signal(&wait_full_buffer2); 1767 | pthread_mutex_unlock(&mutex2); 1768 | } 1769 | return NULL; 1770 | } 1771 | 1772 | void *consume(void *arg){ 1773 | int i; 1774 | char item; 1775 | for(i = 0;i < ITEM_COUNT;i++){ 1776 | pthread_mutex_lock(&mutex2); 1777 | while(buffer_is_empty(2)) 1778 | pthread_cond_wait(&wait_full_buffer2, &mutex2); 1779 | item = get_item(2); 1780 | printf(" comsume item:%c\n", item); 1781 | 1782 | pthread_cond_signal(&wait_empty_buffer2); 1783 | pthread_mutex_unlock(&mutex2); 1784 | } 1785 | return NULL; 1786 | } 1787 | 1788 | int main(){ 1789 | int i; 1790 | in1 = 0; 1791 | in2 = 0; 1792 | out1 = 0; 1793 | out2 = 0; 1794 | pthread_t tids[3]; 1795 | pthread_create(&tids[0],NULL,produce,NULL); 1796 | pthread_create(&tids[1],NULL,compute,NULL); 1797 | pthread_create(&tids[2],NULL,consume,NULL); 1798 | 1799 | pthread_mutex_init(&mutex1, NULL); 1800 | pthread_mutex_init(&mutex2, NULL); 1801 | pthread_cond_init(&wait_empty_buffer1, NULL); 1802 | pthread_cond_init(&wait_full_buffer1, NULL); 1803 | pthread_cond_init(&wait_empty_buffer2, NULL); 1804 | pthread_cond_init(&wait_full_buffer2, NULL); 1805 | 1806 | for(i = 0;i < 3;i++) 1807 | pthread_join(tids[i],NULL); 1808 | pthread_mutex_destroy(&mutex1); 1809 | pthread_mutex_destroy(&mutex2); 1810 | 1811 | 1812 | return 0; 1813 | } 1814 | ``` 1815 | 1816 | #### 3.4.2 pc2 实验结果 1817 | 1818 | ![pc1.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d12dae722aa3.png) 1819 | 1820 | #### 3.4.3 pc2 实验思路 1821 | 1822 | 1.先验知识 1823 | 1824 | (1) pthread_mutex_t 与 pthread_cond_t 1825 | 1826 | | 类型名 | 类型功能 | 声明原型 | 声明示例 | 1827 | | --------------- | ------------------------------ | ------------------------------ | ---------------------------------- | 1828 | | pthread_mutex_t | 声明一个互斥锁(用于线程互斥) | typedef void \*pthread_mutex_t | pthread_mutex_t mutex1,mutex2; | 1829 | | pthread_cond_t | 声明一个条件变量(用于线程同步) | typedef void \*pthread_mutex_t | pthread_cond_t wait_empty_buffer1; | 1830 | 1831 | (2) pthread_mutex_lock() 和 pthread_mutex_unlock() 1832 | 1833 | | 函数名 | 函数功能 | 函数原型 | 函数示例 | 1834 | | ---------------------- | ------------ | --------------------------------------------- | ------------------------------ | 1835 | | pthread_mutex_lock() | 对互斥锁加锁 | int pthread_mutex_lock(pthread_mutex_t \*m) | pthread_mutex_lock(&mutex1); | 1836 | | pthread_mutex_unlock() | 对互斥锁解锁 | int pthread_mutex_unlock(pthread_mutex_t \*m) | pthread_mutex_unlock(&mutex1); | 1837 | 1838 | (3) pthread_cond_wait() 和 pthread_cond_signal() 1839 | 1840 | | 函数名 | 函数功能 | 函数原型 | 函数示例 | 1841 | | --------------------- | -------------- | -------------------------------------------------------------------------- | ------------------------------------------------ | 1842 | | pthread_cond_wait() | 无条件等待 | int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *external_mutex) | pthread_cond_wait(&wait_empty_buffer1, &mutex1); | 1843 | | pthread_cond_signal() | 激活等待的线程 | int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *external_mutex) | pthread_cond_signal(&wait_full_buffer1); | 1844 | 1845 | (4) pthread_mutex_init()、pthread_mutex_destroy() 和 pthread_cond_init() 1846 | 1847 | | 函数名 | 函数功能 | 函数原型 | 函数示例 | 1848 | | ----------------------- | ---------------- | -------------------------------------------------------------------------------- | -------------------------------------------- | 1849 | | pthread_mutex_init() | 互斥锁的初始化 | int pthread_mutex_init(pthread_mutex_t _mutex, const pthread_mutexattr_t _ attr) | pthread_mutex_init(&mutex1, NULL); | 1850 | | pthread_mutex_destory() | 互斥锁的释放 | int pthread_mutex_destroy(pthread_mutex_t \*m) | pthread_mutex_destroy(&mutex1); | 1851 | | pthread_cond_init() | 条件变量的初始化 | int pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *a) | thread_cond_init(&wait_empty_buffer1, NULL); | 1852 | 1853 | (5) pthread_create() 和 pthread_join() 1854 | 1855 | | 函数名 | 函数功能 | 函数原型 | 函数示例 | 1856 | | ---------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------- | 1857 | | pthread_create() | 线程的创建 | int pthread_create(pthread_t *th, const pthread_attr_t *attr, void *(*func)(void *), void *arg) | pthread_create(&tids,NULL,produce,NULL); | 1858 | | pthread_join() | 用于等待一个线程的结束,线程间同步的操作 | int pthread_join(pthread_t t, void \*\*res) | pthread_join(tids,NULL); | 1859 | 1860 | 2.实验思路 1861 | 1862 | (1) 定义两个容量为 4 的 buffer:buffer1 与 buffer2。计算者从 buffer1 取出字符,将小写字符转换为大写字符,放入到 buffer2。消费者从 buffer2 取出字符,将其打印到屏幕上。定义互斥信号量用于进程间互斥,定义条件变量用于进程间同步 1863 | 1864 | ``` 1865 | #define CAPACITY 4 //缓冲区的大小 1866 | #define ITEM_COUNT 8 //字符的数量 1867 | char buffer1[CAPACITY]; 1868 | char buffer2[CAPACITY]; 1869 | int in1,out1; //定义当前buffer1的读指针和写指针 1870 | int in2,out2; //定义当前buffer2的读指针和写指针 1871 | pthread_mutex_t mutex1,mutex2; //定义互斥信号量 1872 | pthread_cond_t wait_empty_buffer1; 1873 | pthread_cond_t wait_full_buffer1; //定义条件变量用于produce与compute之间的同步 1874 | pthread_cond_t wait_empty_buffer2; 1875 | pthread_cond_t wait_full_buffer2; //定义条件变量用于compute与consume之间的同步 1876 | ``` 1877 | 1878 | (2) produce 程序作为 buffer1 的生产者,在操作之前给 buffer1 加锁并将数据存入。 1879 | 1880 | ``` 1881 | void *produce(void *arg){ 1882 | int i; 1883 | char item; 1884 | 1885 | for(i = 0;i < ITEM_COUNT;i++){ 1886 | pthread_mutex_lock(&mutex); //对互斥锁进行加锁 1887 | while(buffer_is_full(1)) 1888 | pthread_cond_wait(&wait_empty_buffer1, &mutex); //P操作:若buffer1满了就等待其为空 1889 | item = 'a' + i; 1890 | put_item(item,1); 1891 | printf("produce item:%c\n",item); 1892 | 1893 | pthread_cond_signal(&wait_full_buffer1); //V操作:将buffer1的数据缓冲区数目(wait_full_buffer1) + 1 1894 | pthread_mutex_unlock(&mutex); //释放信号量 1895 | } 1896 | return NULL; 1897 | } 1898 | ``` 1899 | 1900 | (3) compute 程序先作为 buffer1 的消费者,给 buffer1 加锁并取数;计算者将小写字母变成大写字母;计最后再作为 buffer2 的生产者,给 buffer2 加锁并存数。 1901 | 1902 | ``` 1903 | void *compute(void *arg){ 1904 | int i; 1905 | char item; 1906 | 1907 | for(i = 0;i < ITEM_COUNT;i++){ 1908 | pthread_mutex_lock(&mutex1); //对信号量1加锁 1909 | while(buffer_is_empty(1)) 1910 | pthread_cond_wait(&wait_full_buffer1, &mutex1); //P操作:若buffer1为空则持续等待 1911 | item = get_item(1); 1912 | //printf(" compute get item:%c\n",item); 1913 | pthread_cond_signal(&wait_empty_buffer1); //V操作:将buffer1的数据缓冲区数目(wait_empty_buffer1)-1 1914 | pthread_mutex_unlock(&mutex1); //释放信号量1 1915 | 1916 | item -= 32; 1917 | 1918 | pthread_mutex_lock(&mutex2); //对信号量2加锁 1919 | while(buffer_is_full(2)) 1920 | pthread_cond_wait(&wait_empty_buffer2, &mutex2);//P操作:若buffer2满了则持续等待 1921 | put_item(item,2); 1922 | printf(" compute put item:%c\n", item); 1923 | pthread_cond_signal(&wait_full_buffer2); //V操作:将buffer2的数据缓冲区数目(wait_full_buffer2)+1 1924 | pthread_mutex_unlock(&mutex2); //释放信号量2 1925 | } 1926 | return NULL; 1927 | } 1928 | ``` 1929 | 1930 | (4)消费者作为 buffer2 的消费者,给 buffer2 加锁并取数字。 1931 | 1932 | ``` 1933 | void *consume(void *arg){ 1934 | int i; 1935 | char item; 1936 | for(i = 0;i < ITEM_COUNT;i++){ 1937 | pthread_mutex_lock(&mutex2); //对信号量2加锁 1938 | while(buffer_is_empty(2)) 1939 | pthread_cond_wait(&wait_full_buffer2, &mutex2); //P操作:若buffer2为空则持续等待 1940 | item = get_item(2); 1941 | printf(" comsume item:%c\n", item); 1942 | pthread_cond_signal(&wait_empty_buffer2); //V操作:将buffer2的数据缓冲区数目(wait_empty_buffer2)-1 1943 | pthread_mutex_unlock(&mutex2); //释放信号量2 1944 | } 1945 | return NULL; 1946 | } 1947 | ``` 1948 | 1949 | (5)在主函数中创建三个线程分别用于承担生产者,计算者与消费者。对线程进行初始化,并且定义两个锁用于线程间互斥,再定义四个信号量用于线程间同步,再将三个进程都调用 pthread_join()函数等待线程结束,最终对互斥锁进行注销。 1950 | 1951 | ``` 1952 | int main(){ 1953 | int i; 1954 | in1 = 0; 1955 | in2 = 0; 1956 | out1 = 0; 1957 | out2 = 0; 1958 | pthread_t tids[3]; 1959 | pthread_create(&tids[0],NULL,produce,NULL); 1960 | pthread_create(&tids[1],NULL,compute,NULL); 1961 | pthread_create(&tids[2],NULL,consume,NULL); 1962 | 1963 | pthread_mutex_init(&mutex1, NULL); 1964 | pthread_mutex_init(&mutex2, NULL); 1965 | pthread_cond_init(&wait_empty_buffer1, NULL); 1966 | pthread_cond_init(&wait_full_buffer1, NULL); 1967 | pthread_cond_init(&wait_empty_buffer2, NULL); 1968 | pthread_cond_init(&wait_full_buffer2, NULL); 1969 | 1970 | for(i = 0;i < 3;i++) 1971 | pthread_join(tids[i],NULL); 1972 | pthread_mutex_destroy(&mutex1); 1973 | pthread_mutex_destroy(&mutex2); 1974 | 1975 | return 0; 1976 | } 1977 | ``` 1978 | 1979 | ### 3.5 pc2.c: 使用信号量解决生产者、计算者、消费者问题 1980 | 1981 | - 功能和前面的实验相同,使用信号量解决 1982 | 1983 | #### 3.5.1 pc2 实验代码 1984 | 1985 | ``` 1986 | #include 1987 | #include 1988 | #include 1989 | #include 1990 | #define CAPACITY 4 1991 | 1992 | char buffer1[CAPACITY]; 1993 | char buffer2[CAPACITY]; 1994 | int in1,out1; 1995 | int in2,out2; 1996 | 1997 | int buffer_is_empty(int index){ 1998 | if(index == 1) 1999 | return in1 == out1; 2000 | if(index == 2) 2001 | return in2 == out2; 2002 | else 2003 | printf("Don`t exist this buffer!,Empty"); 2004 | } 2005 | 2006 | int buffer_is_full(int index){ 2007 | if(index == 1) 2008 | return (in1 + 1) % CAPACITY == out1; 2009 | if(index == 2) 2010 | return (in2 + 1) % CAPACITY == out2; 2011 | else 2012 | printf("Don`t exist this buffer!,Full"); 2013 | } 2014 | char get_item(int index){ 2015 | char item; 2016 | if(index == 1){ 2017 | item = buffer1[out1]; 2018 | out1 = (out1 + 1) % CAPACITY; 2019 | } 2020 | if(index == 2){ 2021 | item = buffer2[out2]; 2022 | out2 = (out2 + 1) % CAPACITY; 2023 | } 2024 | //else 2025 | // printf("Don`t exist this buffer!,Get%d\n",index); 2026 | return item; 2027 | } 2028 | 2029 | void put_item(char item, int index){ 2030 | if(index == 1){ 2031 | buffer1[in1] = item; 2032 | in1 = (in1 + 1) % CAPACITY; 2033 | } 2034 | if(index == 2){ 2035 | buffer2[in2] = item; 2036 | in2 = (in2 + 1) % CAPACITY; 2037 | } 2038 | //else 2039 | // printf("Don`t exist this buffer!Put%c %d\n",item,index); 2040 | } 2041 | 2042 | typedef struct{ 2043 | int value; 2044 | pthread_mutex_t mutex; 2045 | pthread_cond_t cond; 2046 | }sema_t; 2047 | 2048 | void sema_init(sema_t *sema, int value){ 2049 | sema->value = value; 2050 | pthread_mutex_init(&sema->mutex, NULL); 2051 | pthread_cond_init(&sema->cond, NULL); 2052 | } 2053 | 2054 | void sema_wait(sema_t *sema){ 2055 | pthread_mutex_lock(&sema->mutex); 2056 | while(sema->value <= 0) 2057 | pthread_cond_wait(&sema->cond, &sema->mutex); 2058 | sema->value--; 2059 | pthread_mutex_unlock(&sema->mutex); 2060 | } 2061 | 2062 | void sema_signal(sema_t *sema){ 2063 | pthread_mutex_lock(&sema->mutex); 2064 | ++sema->value; 2065 | pthread_cond_signal(&sema->cond); 2066 | pthread_mutex_unlock(&sema->mutex); 2067 | } 2068 | 2069 | sema_t mutex_sema1,mutex_sema2; 2070 | sema_t empty_buffer_sema1; 2071 | sema_t full_buffer_sema1; 2072 | sema_t empty_buffer_sema2; 2073 | sema_t full_buffer_sema2; 2074 | 2075 | volatile int global = 0; 2076 | 2077 | #define ITEM_COUNT 8 2078 | 2079 | void *produce(void *arg){ 2080 | int i; 2081 | char item; 2082 | 2083 | for(i = 0;i < ITEM_COUNT;i++){ 2084 | sema_wait(&empty_buffer_sema1); 2085 | sema_wait(&mutex_sema1); 2086 | 2087 | item = 'a' + i; 2088 | put_item(item,1); 2089 | printf("produce item:%c\n",item); 2090 | 2091 | sema_signal(&mutex_sema1); 2092 | sema_signal(&full_buffer_sema1); 2093 | } 2094 | return NULL; 2095 | } 2096 | void *compute(void *arg){ 2097 | int i; 2098 | char item; 2099 | for(i = 0;i < ITEM_COUNT;i++){ 2100 | sema_wait(&full_buffer_sema1); 2101 | sema_wait(&mutex_sema1); 2102 | 2103 | item = get_item(1); 2104 | // printf(" compute get item:%c\n",item); 2105 | 2106 | sema_signal(&mutex_sema1); 2107 | sema_signal(&empty_buffer_sema1); 2108 | 2109 | item -= 32; 2110 | 2111 | sema_wait(&empty_buffer_sema2); 2112 | sema_wait(&mutex_sema2); 2113 | 2114 | put_item(item,2); 2115 | printf(" compute put item:%c\n", item); 2116 | 2117 | sema_signal(&mutex_sema2); 2118 | sema_signal(&full_buffer_sema2); 2119 | } 2120 | return NULL; 2121 | } 2122 | 2123 | void *consume(void *arg){ 2124 | int i; 2125 | char item; 2126 | for(i = 0;i < ITEM_COUNT;i++){ 2127 | 2128 | sema_wait(&full_buffer_sema2); 2129 | sema_wait(&mutex_sema2); 2130 | 2131 | item = get_item(2); 2132 | printf(" comsume item:%c\n", item); 2133 | 2134 | sema_signal(&mutex_sema2); 2135 | sema_signal(&empty_buffer_sema2); 2136 | } 2137 | return NULL; 2138 | } 2139 | 2140 | int main(){ 2141 | int i; 2142 | in1 = 0; 2143 | in2 = 0; 2144 | out1 = 0; 2145 | out2 = 0; 2146 | pthread_t tids[3]; 2147 | 2148 | sema_init(&mutex_sema1, 1); 2149 | sema_init(&mutex_sema2, 1); 2150 | sema_init(&empty_buffer_sema1,CAPACITY - 1); 2151 | sema_init(&full_buffer_sema1,0); 2152 | sema_init(&empty_buffer_sema2,CAPACITY - 1); 2153 | sema_init(&full_buffer_sema1,0); 2154 | 2155 | 2156 | pthread_create(&tids[0],NULL,produce,NULL); 2157 | pthread_create(&tids[1],NULL,compute,NULL); 2158 | pthread_create(&tids[2],NULL,consume,NULL); 2159 | 2160 | for(i = 0;i < 3;i++) 2161 | pthread_join(tids[i],NULL); 2162 | 2163 | 2164 | return 0; 2165 | } 2166 | ``` 2167 | 2168 | #### 3.5.2 pc2 实验结果 2169 | 2170 | ![pc2.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d12e7f6a73a3.png) 2171 | 2172 | #### 3.5.3 pc2 实验思路 2173 | 2174 | (1) 信号量的实现 2175 | 2176 | 此题与上题思路相同,区别在于实现的时候利用信号量。信号量的定义、初始化、wait 和 signal 定义如下,初始化时可以送入信号量的初始个数,wait 一次减少一次信号量个数,signal 一次则增加一次信号量个数。 2177 | 2178 | ``` 2179 | typedef struct{ 2180 | int value; 2181 | pthread_mutex_t mutex; 2182 | pthread_cond_t cond; 2183 | }sema_t; 2184 | 2185 | void sema_init(sema_t *sema, int value){ 2186 | sema->value = value; 2187 | pthread_mutex_init(&sema->mutex, NULL); 2188 | pthread_cond_init(&sema->cond, NULL); 2189 | } 2190 | 2191 | void sema_wait(sema_t *sema){ 2192 | pthread_mutex_lock(&sema->mutex); 2193 | while(sema->value <= 0) 2194 | pthread_cond_wait(&sema->cond, &sema->mutex); 2195 | sema->value--; 2196 | pthread_mutex_unlock(&sema->mutex); 2197 | } 2198 | 2199 | void sema_signal(sema_t *sema){ 2200 | pthread_mutex_lock(&sema->mutex); 2201 | ++sema->value; 2202 | pthread_cond_signal(&sema->cond); 2203 | pthread_mutex_unlock(&sema->mutex); 2204 | } 2205 | ``` 2206 | 2207 | (2)定义信号量并使用 2208 | 2209 | 定义两个信号量 mutex_sema1,mutex_sema2,分别对(生产者-计算者)与(计算者-消费者)进行线程间互斥。此外也定义了四个信号量 2210 | 对共享变量 buffer1,buffer2 进行线程间同步。 2211 | 2212 | 在生产者、计算者、消费者的函数中,先进行 P 操作等待互斥信号量(上锁),再 P 操作获取同步信号量,对 buffer 中的数据进行操作后,V 操作释放互斥信号量及同步信号量(解锁)。这里值得注意的是,需要 P 操作需要先获取同步信号量再对互斥信号量进行上锁,不然可能造饥饿的现象。 2213 | 2214 | ``` 2215 | sema_t mutex_sema1,mutex_sema2; 2216 | sema_t empty_buffer_sema1; 2217 | sema_t full_buffer_sema1; 2218 | sema_t empty_buffer_sema2; 2219 | sema_t full_buffer_sema2; 2220 | void *produce(void *arg){ 2221 | int i; 2222 | char item; 2223 | 2224 | for(i = 0;i < ITEM_COUNT;i++){ 2225 | sema_wait(&empty_buffer_sema1); 2226 | sema_wait(&mutex_sema1); 2227 | 2228 | item = 'a' + i; 2229 | put_item(item,1); 2230 | printf("produce item:%c\n",item); 2231 | 2232 | sema_signal(&mutex_sema1); 2233 | sema_signal(&full_buffer_sema1); 2234 | } 2235 | return NULL; 2236 | } 2237 | void *compute(void *arg){ 2238 | int i; 2239 | char item; 2240 | for(i = 0;i < ITEM_COUNT;i++){ 2241 | sema_wait(&full_buffer_sema1); 2242 | sema_wait(&mutex_sema1); 2243 | 2244 | item = get_item(1); 2245 | // printf(" compute get item:%c\n",item); 2246 | 2247 | sema_signal(&mutex_sema1); 2248 | sema_signal(&empty_buffer_sema1); 2249 | 2250 | item -= 32; 2251 | 2252 | sema_wait(&empty_buffer_sema2); 2253 | sema_wait(&mutex_sema2); 2254 | 2255 | put_item(item,2); 2256 | printf(" compute put item:%c\n", item); 2257 | 2258 | sema_signal(&mutex_sema2); 2259 | sema_signal(&full_buffer_sema2); 2260 | } 2261 | return NULL; 2262 | } 2263 | 2264 | void *consume(void *arg){ 2265 | int i; 2266 | char item; 2267 | for(i = 0;i < ITEM_COUNT;i++){ 2268 | 2269 | sema_wait(&full_buffer_sema2); 2270 | sema_wait(&mutex_sema2); 2271 | 2272 | item = get_item(2); 2273 | printf(" comsume item:%c\n", item); 2274 | 2275 | sema_signal(&mutex_sema2); 2276 | sema_signal(&empty_buffer_sema2); 2277 | } 2278 | return NULL; 2279 | } 2280 | ``` 2281 | 2282 | (3) main 函数中开启三个线程分别对应生产者、计算者、消费者,再对两个互斥信号量以及四个同步信号量进行初始化,调用 pthread_join 函数等待三个进程的结束即可。 2283 | 2284 | ``` 2285 | int main(){ 2286 | int i; 2287 | in1 = 0; 2288 | in2 = 0; 2289 | out1 = 0; 2290 | out2 = 0; 2291 | pthread_t tids[3]; 2292 | 2293 | sema_init(&mutex_sema1, 1); 2294 | sema_init(&mutex_sema2, 1); 2295 | sema_init(&empty_buffer_sema1,CAPACITY - 1); 2296 | sema_init(&full_buffer_sema1,0); 2297 | sema_init(&empty_buffer_sema2,CAPACITY - 1); 2298 | sema_init(&full_buffer_sema1,0); 2299 | 2300 | 2301 | pthread_create(&tids[0],NULL,produce,NULL); 2302 | pthread_create(&tids[1],NULL,compute,NULL); 2303 | pthread_create(&tids[2],NULL,consume,NULL); 2304 | 2305 | for(i = 0;i < 3;i++) 2306 | pthread_join(tids[i],NULL); 2307 | 2308 | 2309 | return 0; 2310 | } 2311 | 2312 | ``` 2313 | 2314 | ### 3.6 ring.c: 创建 N 个线程,它们构成一个环 2315 | 2316 | - 创建 N 个线程:T1、T2、T3、… TN 2317 | - T1 向 T2 发送整数 1 2318 | - T2 收到后将整数加 1 2319 | - T2 向 T3 发送整数 2 2320 | - T3 收到后将整数加 1 2321 | - T3 向 T4 发送整数 3 2322 | - … 2323 | - TN 收到后将整数加 1 2324 | - TN 向 T1 发送整数 N 2325 | 2326 | #### 3.6.1 ring 实验代码 2327 | 2328 | ``` 2329 | #include 2330 | #include 2331 | #include 2332 | #include 2333 | #define N 100 2334 | int buffer = 0; 2335 | 2336 | void *add(void *arg){ 2337 | int *num = (int *)arg; 2338 | num[0]++; 2339 | int *result = num; 2340 | return (void *)result; 2341 | } 2342 | 2343 | void init(int a[N][2]){ 2344 | int i; 2345 | for(i = 0;i < N;i++){ 2346 | a[i][0] = 0; 2347 | a[i][1] = i; 2348 | } 2349 | } 2350 | 2351 | 2352 | int main(){ 2353 | int i = 0; 2354 | int array[N][2]; 2355 | init(array); 2356 | int *result; 2357 | 2358 | pthread_t tids[N]; 2359 | pthread_create(&tids[0],NULL,add,(void *)array[0]); 2360 | pthread_join(tids[0], (void *)&result); 2361 | 2362 | while(i < N){ 2363 | printf("from T[%d]", i+1); 2364 | i = (i+1) % N; 2365 | printf("to T[%d] send %d\n",i+1,result[0]); 2366 | pthread_create(&tids[i],NULL,add,result); 2367 | pthread_join(tids[i], (void *)&result); 2368 | if(i == 0) 2369 | break; 2370 | // sleep(1); 2371 | } 2372 | 2373 | return 0; 2374 | } 2375 | 2376 | ``` 2377 | 2378 | #### 3.6.2 ring 实验结果 2379 | 2380 | ![ring-1.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d132291b95e4.png) 2381 | ![ring-2.png](https://muyun-blog-pic.oss-cn-shanghai.aliyuncs.com/2019/06/26/5d1322298eb0f.png) 2382 | 2383 | #### 3.6.3 ring 实验思路 2384 | 2385 | (1) 创建 N 个容量为 2 的缓冲区 array[N][2],初始化每个缓冲区的第一个数字都为 0,第二个数字为当前缓冲区的编号。接着定义了一个数字数组 result.创建 N 个线程,对第一个线程进行初始化,该进程运行 add 函数,然后将 array[0]作为参数传入 add 函数中。并调用 pthread_join()函数等待线程结束。 2386 | 2387 | ``` 2388 | void *add(void *arg){ 2389 | int *num = (int *)arg; 2390 | num[0]++; 2391 | int *result = num; 2392 | return (void *)result; 2393 | } 2394 | 2395 | void init(int a[N][2]){ 2396 | int i; 2397 | for(i = 0;i < N;i++){ 2398 | a[i][0] = 0; 2399 | a[i][1] = i; 2400 | } 2401 | } 2402 | 2403 | int i = 0; 2404 | int array[N][2]; 2405 | init(array); 2406 | int *result; 2407 | 2408 | pthread_t tids[N]; 2409 | pthreaad_create(&tids[0],NULL,add,(void *)array[0]); 2410 | pthread_join(tids[0], (void *)&result); 2411 | 2412 | ``` 2413 | 2414 | (2) 在循环中,首先打印发送方的信息,然后 i 循环加 1,然后打印接收方的信息并创建线程,将收到的数作为参数传入线程中执行 add 函数,并调用 pthread_join()函数等待线程结束。当 i 循环加 1 到 0 到 i 为 0 时(又返回第一个缓冲区)时结束。 2415 | 2416 | ``` 2417 | while(i < N){ 2418 | printf("from T[%d]", i+1); 2419 | i = (i+1) % N; 2420 | printf("to T[%d] send %d\n", i+1, result[0]); 2421 | pthread_create(&tids[i],NULL,add,result); 2422 | pthread_join(tids[i], (void *)&result); 2423 | if(i == 0) 2424 | break; 2425 | // sleep(1); 2426 | } 2427 | ``` 2428 | --------------------------------------------------------------------------------