目录
一、Linux操作系统
(1)第1关:Linux初体验
(2)第2关:Linux常用命令
(3)第3关:Linux 查询命令帮助语句
二、Linux之进程管理—(重点)
(1)第1关:获取进程常见属性
(2)第2关:进程创建操作-fork
(3)第3关:进程创建操作-vfork
(4)第4关:进程终止
三、生产者消费者问题实践
(1)第1关:生产者消费者问题实践
(2)第2关:进程互斥和同步
四、基于信号量的进程间通信
(1)第1关:信号量IPC操作考查
五、基于命名管道与信号的进程间通信
(1)第1关:命名管道与信号IPC操作考查
六、 Linux vi/vim编辑器(难度:简单)
(1)第1关:vi/vim基本用法
(2)第2关:vi/vim工作模式切换
(3)第3关:vi/vim命令模式
(4)第4关:vi/vim底线命令模式(重点)
七、读文件系统函数(难度:简单)
(1)第1关:读文件系统函数
八、写文件系统函数(难度:中等)
(1)第1关:写文件系统函数
九、进程基础操作(难度:简单)
(1)第1关:进程基础操作考察
本篇博客的主要内容是在做大题时遇到的问题和一些总结。(具体答案看我之前的博客)
一、Linux操作系统
(1)第1关:Linux初体验
(2)第2关:Linux常用命令
- 将
newfile
文件复制一份到newdir
目录下并命名为newfileCpy
。cp newfile newdir/newfileCpy
(3)第3关:Linux 查询命令帮助语句
- linux中使用
man
命令来查询命令的帮助文件
二、Linux之进程管理—(重点)
(1)第1关:获取进程常见属性
- 获取进程本身的进程
ID
的系统调用函数是getpid()。
- 获取父进程的进程
ID
的系统调用函数是getppid()。
(2)第2关:进程创建操作-fork
- 这题需要注意的地方:pid_t pid =fork();
(3)第3关:进程创建操作-vfork
- 这题需要注意的地方:pid_t pid = vfork();
- 子进程中输出"Children"字符串(提示:需要换行)
(4)第4关:进程终止
用这个注册函数:atexit()
和on_exit()
调用成功返回0
;调用失败返回一个非零值。void exit(){printf("%d",getpid());}if(atexit(exit)){}
三、生产者消费者问题实践
(1)第1关:生产者消费者问题实践
- 观察题目代码给出的生产者函数。根据这个来写!!
sem_t empty; :类似等待一个信号(生产)
sem_t full; :类似等待一个信号(消费)
- sem_wait(&empty);
- sem_wait(&full);
(在每一个操作时和释放时都要记得加锁和解锁)
- 加锁 pthread_mutex_lock(&mutex);
- 释放锁 pthread_mutex_unlock(&mutex);
锁对象:pthread_mutex_t mutex;
- 设置一个参数(仿照生产者函数)int nextc = 0;
- 先给一个等待消费条件:sem_wait(&full);
- 再加锁:pthread_mutex_lock(&mutex);
意思是:从之前生产了的东西拿东西出来消费:nextc=buffer[out];
与生产者函数中用到的一样:int out = 0;
这个跟着改:printf("Consume one message:%d\n", nextc);
fflush(stdout); //printf后请一定调用这句刷新输出缓存out = (out + 1) % SIZE;
- out = (out + 1) % SIZE; (这个跟生产者函数一样,对着改就行)
pthread_mutex_unlock(&mutex); ——> 再解锁
最后记得给一个消费完的信号:sem_post(&empty); 。意思其实就是消费完,给一个叫"空"的信号。
具体的答案《消费:Consumer()函数》
void *Consumer() {// ============================= begin ======================//请补充消费者线程函数代码int nextc = 0;int i = 0;for(; i < 10; ++i){ int time = rand() % 10 + 1;usleep(time*100000); sem_wait(&full); pthread_mutex_lock(&mutex);nextc=buffer[out];printf("Consume one message:%d\n", nextc);fflush(stdout);//printf后请一定调用这句刷新输出缓存out = (out + 1) % SIZE;pthread_mutex_unlock(&mutex); //互斥锁解锁sem_post(&empty);}// ============================= end ========================}
对比题目提供的《生产函数:Producer()》
int in = 0; int out = 0; int buffer[SIZE]; sem_t empty; sem_t full; pthread_mutex_t mutex;void *Producer() {int nextp = 0;int i = 0;for(; i < 10; ++i){ int time = rand() % 10 + 1;usleep(time*100000); sem_wait(&empty); pthread_mutex_lock(&mutex);buffer[in] = nextc;printf("Produce one message:%d\n", nextp);fflush(stdout);//printf后请一定调用这句刷新输出缓存in = (in + 1) % SIZE;pthread_mutex_unlock(&mutex); //互斥锁解锁sem_post(&full);} }
(2)第2关:进程互斥和同步
(这个就简单了!!结合上面学的东西,以及仿照这个题目女儿的"苹果"消费函数写就好)
- 把消费等待的信号换成"orange(桔子)"
- 把printf(....)输出换一下就好了
- 儿子消费函数答案
void *Son() {// ============================== begin ===========================//请添加儿子线程的函数代码while(1){int time = rand() % 10 + 1; //随机使程序睡眠0点几秒usleep(time * 100000); sem_wait(&orange); pthread_mutex_lock(&mutex);printf("儿子取了一个桔子\n") ;fflush(stdout);pthread_mutex_unlock(&mutex); //互斥锁解锁sem_post(&empty);}// ============================== end ============================== }
四、基于信号量的进程间通信
(1)第1关:信号量IPC操作考查
- 搞清楚函数:
semctl(int semid,int semnum,int cmd,...);
semid要操作的信号量集合:(题目中给出变量:"
int semid;")
semnum集合中信号量的编号(题目中就是:"i")
cmd执行的操作:(题目中有提示:
#define GETVAL 获取信号量的值返回信号的值
)
具体答案如下:
(此代码不严谨!!因为没有判断是否函数调用成功!但是满足评测要求)
for ( i = 0 ; i < MAX_SEMAPHORES ; i++ ){// =================================== begin ===============================/*请调用semctl函数,读取并输出与上述数组输出相同的输出*/// 注意:getval_arg.val 在这里不需要设置,因为 GETVAL 不使用它 int x = semctl(semid, i, GETVAL); printf("Semaphore %d, value %d\n", i, x); // =================================== end ===============================}
更完整、更严谨的答案:
(记得还要在顶部导入包:#include <stdlib.h> //以使用exit函数)for ( i = 0 ; i < MAX_SEMAPHORES ; i++ ){// =================================== begin ===============================/*请调用semctl函数,读取并输出与上述数组输出相同的输出*/// 注意:getval_arg.val 在这里不需要设置,因为 GETVAL 不使用它 int x = semctl(semid, i, GETVAL); if (x == -1) { printf("GETVAL for semaphore %d failed (%d)\n", i, errno); exit(EXIT_FAILURE); }printf("Semaphore %d, value %d\n", i, x); // =================================== end ===============================}
五、基于命名管道与信号的进程间通信
(1)第1关:命名管道与信号IPC操作考查
(没啥好说的,不会的操作系统考试就靠记呗!!)
- sleep(1); 休眠1秒
- 打开读通道——> open("FIFO",O_RDONLY);
- 打开写通道——> open("FIFO",O_WRONLY);
- 开始写——>write(fd,"heool0penEuler",1);
答案如下:
if(pid==0){// ============================= begin =========================/*子进程打开读管道,随后关闭管道*/int fd;fd = open("FIFO",O_RDONLY); /*rd->only 写*//*关闭*/close(fd);}else{/*父进程打开写通道,休眠1秒,尝试写入*/int fd;fd = open("FIFO",O_WRONLY); /*wr->only 写*/int ret;sleep(1); /*休眠1秒*//*写入*/ret = write(fd,"heool0penEuler",1);// ============================= end =========================}
六、 Linux vi/vim编辑器(难度:简单)
(注意这类题目在操作之前需要初始化任务环境)
(1)第1关:vi/vim基本用法
(2)第2关:vi/vim工作模式切换
- wq :保存并退出
- i:插入
(3)第3关:vi/vim命令模式
- dd:删除
- yy:复制
- p:粘贴
(4)第4关:vi/vim底线命令模式(重点)
- 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2。 :1,$s/word1/word2/g
将文件第2-5行内容另存为oldFileCpy.txt文件:2,5 w oldFileCpy.txt。
七、读文件系统函数(难度:简单)
(1)第1关:读文件系统函数
(此题注意:知道read()函数是啥就行了。其次知道其返回值和其函数的参数)
- 函数原型:read(int fd, void *buf, size_t count);
- fd:看上文(读文件的地址)
- *buf:字符数组缓冲区的位置
- 最后这个size_t count:就是读到的全部字符的个数——> sizeof(buffer)-1
#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #define rwmode 0 int main() {int fd;char buffer[1024];int n;fd = open("/data/workspace/myshixun/case1/testFIle", rwmode);if (fd < 0){printf("Open file error!\n");exit(1);}elseprintf("open testFIle ok!\n");//-------------begin---------------------- //请使用read函数将其读入buffer中n = read(fd,buffer,sizeof(buffer)-1);//--------------end---------------------- buffer[n] = '\0';printf("%s\n", buffer);close(fd);return 0; }
八、写文件系统函数(难度:中等)
(1)第1关:写文件系统函数
(这题其实就是一个综合。先用read()读函数,再用write()写函数)
函数原型:ssize_t write(int fd, const void *buf, size_t count);
读的文件的地址题目也给出:int resource_fd
char buffer[FILESIZE]:字符数组
- #define FILESIZE 1024 (该字符数组最大容量,也是题目要求读取的量)
- 所以:(read(resource_fd,buffer,FILESIZE ))>0,因为读到了就要返回得到的个数。
char buffer[FILESIZE], *p; p = buffer; :要写入的字符数组信息地址在p
写的目的文件地址题目也给出了:int destination_fd
具体要写的字符个数(前面被赋值):readbytes = read(resource_fd,buffer,FILESIZE)
所以:(writebytes = write(destination_fd,p,readbytes))>0,因为写到了就要返回个数
综合解答:
#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #define resource_mode 0 #define destination_mode 0774 #define FILESIZE 1024int main(int argc, char *argv[]) {int resource_fd, destination_fd;char buffer[FILESIZE], *p;int readbytes, writebytes;if (argc != 3){printf("Usage:copy from resource file to destination file\n %s src_file dest_file\n", argv[0]);exit(0);}if ((resource_fd = open(argv[1], resource_mode)) == -1){perror("Can't open source file");exit(0);}if ((destination_fd = creat(argv[2], destination_mode)) == -1){perror("Can't create destination file");exit(0);}// ======================= begin =======================================// 请使用read函数读取前1024字节的内容读到缓冲区buffer中while ((readbytes = read(resource_fd,buffer,FILESIZE))>0)// ========================== end ======================================={p = buffer;if ((readbytes == -1) && (errno != EINTR))break;else if (readbytes > 0){// ======================= begin =======================================// 请使用write函数读取到的前1024字节的内容写到目的文件中while ((writebytes = write(destination_fd,p,readbytes))>0)// ========================== end ======================================={if ((writebytes == -1) && (errno != EINTR))break;else if (writebytes == readbytes)break;else if (writebytes > 0){p += writebytes;readbytes -= writebytes;}}if (writebytes == -1)break;}}close(resource_fd);close(destination_fd);return 0; }
九、进程基础操作(难度:简单)
(1)第1关:进程基础操作考察
(这一关没啥好说的,难度很简单)
- 了解fork()函数即可
- 注意空格的输出(父、子进程都一样):printf("bye! ");
#include<stdio.h> #include<unistd.h> #include<fcntl.h> #include<stdlib.h> int main(int argc,char *argv[]) {/*请开始填写*/pid_t pid =fork();if(pid==0){printf("bye! ");}else if(pid>0){printf("bye! ");}return 0; }