NUAA操作系统OS实验及上机考试记录

这篇具有很好参考价值的文章主要介绍了NUAA操作系统OS实验及上机考试记录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

记录nuaa操作系统实验题目

将代码分享出来是为了学弟学妹更好的学习复习,并不是为copy提供便利。里边包含了平时的job及近几年的考试题,我已将代码上传至github:
https://github.com/changyan-maker/NUAA_OS

最后参加机考我拿了90+,来源于平时认真完成job以及考前认真刷题准备,所以平时不要copy代码投机取巧哦,要理解其中的思路,在机考的过程中才能游刃有余!


exam

往年考试题的题目和代码已上传至github,建议考前多刷两遍,
https://github.com/changyan-maker/NUAA_OS
毕竟考试相对综合,个人觉得考前时间充裕的话,先刷一遍作业的job,最后再刷往年考试题会很有感觉。我们19级也就是2022年考的特别难,基本没有几个同学完全运行出正确结果,老师最后都是按照过程给分,这里将题目分享出来只是为了长长见识,毕竟在考试前我也没太见过这种题,考试过程中基本全靠临场发挥。不过前几年的题目还是很简单的,听说拿满分的人也有,所以对于2018、2019、2021年的题目,学弟学妹一定要自己写出来,拿下那些题型!

job3

1. myecho.c

myecho.c的功能与系统echo程序相同
接受命令行参数,并将参数打印出来,例子如下:
$ ./myecho x
x
$ ./myecho a b c
a b c

#include<stdio.h>
int main(int argc, char *argv[])
{
	int i;
	printf("argc=%d\n",argc);
	for(i=1;i<argc;i++)
		printf("%s ",argv[i]);
	printf("\n");
	return 0;
}

2. mycat.c

mycat.c的功能与系统cat程序相同
mycat将指定的文件内容输出到屏幕,例子如下:
要求使用系统调用open/read/write/close实现
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
…
$ ./mycat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
…

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
	int fd;
	mode_t mode = 0777;
	fd = open(argv[1],O_RDONLY,mode);
	char ch;
	int count = read(fd, &ch, sizeof(ch));
	while(count)
	{
		printf("%c", ch);
		count = read(fd, &ch, sizeof(ch));
	}
	close(fd);
	return 0;
}

3. mycp.c

mycp.c的功能与系统cp程序相同
将源文件复制到目标文件,例子如下:
要求使用系统调用open/read/write/close实现
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
…
$ ./mycp /etc/passwd passwd.bak
$ cat passwd.bak
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
…

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
	mode_t mode = 0777;
	int fd1 = open(argv[1], O_RDONLY, mode);
	int fd2 = creat(argv[2],mode);
	char ch;
	int count = read(fd1, &ch, sizeof(ch));
	int count2;
	while(count)
	{
		count2 = write(fd2, &ch, sizeof(ch));
		count = read(fd1, &ch, sizeof(ch));
	}
	close(fd1);
	close(fd2);
	return 0;
}

4. mysys.c

mysys的功能与系统函数system相同,要求用进程管理相关系统调用自己实现一遍
使用fork/exec/wait系统调用实现mysys
不能通过调用系统函数system实现mysys
测试程序
#include <stdio.h>

void mysys(char *command)
{
 实现该函数,该函数执行一条命令,并等待该命令执行结束
}

int main()
{
 printf(“--------------------------------------------------\n”);
 mysys(“echo HELLO WORLD”);
 printf(“--------------------------------------------------\n”);
 mysys(“ls /”);
 printf(“--------------------------------------------------\n”);
 return 0;
}
测试程序的输出结果
--------------------------------------------------
HELLO WORLD
--------------------------------------------------
bin core home lib mnt root snap tmp vmlinuz
boot dev initrd.img lost+found opt run srv usr vmlinuz.old
cdrom etc initrd.img.old media proc sbin sys var
--------------------------------------------------

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include<stdlib.h>

void mysys(char *command)
{
	int pid;
	pid = fork();
	if(pid==0){
		int i=0;
		char a[5][20];
		int num = 0;
		int j=0;
		while(command[i]!='\0')
		{
			if(command[i]!=' '){
				a[num][j++] = command[i];
			}		
			else{
				a[num++][j++] = '\0';
				j=0;
			}
			i++;
		}
		a[num][j++] = '\0';
		int error;

		char *argv[5];
		for(i=0;i<=num;i++){
			argv[i] = (char *)malloc(sizeof(char)*20);
			strcpy(argv[i],a[i]);
		}
		argv[i] = NULL;
		error = execvp(argv[0],argv);
		if(error<0)
			perror("execv");
	}
	wait(NULL);
}

int main()
{
	printf("--------------------------------------------------\n");
	mysys("echo HELLO WORLD");	
	printf("--------------------------------------------------\n");
	mysys("ls /");
	printf("--------------------------------------------------\n");
	return 0;
}

5. sh1.c

该程序读取用户输入的命令,调用函数mysys(上一个作业)执行用户的命令,示例如下
# 编译sh1.c
$ cc -o sh1 sh1.c

# 执行sh1
$ ./sh

# sh1打印提示符>,同时读取用户输入的命令echo,并执行输出结果
> echo a b c
a b c

# sh1打印提示符>,同时读取用户输入的命令cat,并执行输出结果
> cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
实现内置命令cd、pwd、exit

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include<stdlib.h>

int main()
{
	while(1){
		printf("%s","> ");
		char str[105];
		fgets(str,100,stdin);
		int i=0;
		while(str[i]!='\n')
			i++;
		str[i] = '\0';
		
		i=0;
		char a[5][20];
		int num = 0;
		int j=0;
		while(str[i]!='\0')
		{
			if(str[i]!=' '){
				a[num][j++] = str[i];
			}		
			else{
				a[num++][j++] = '\0';
				j=0;
			}
			i++;
		}
		a[num][j++] = '\0';
		int error;
		char *argv[5];
		for(i=0;i<=num;i++){
			argv[i] = (char *)malloc(sizeof(char)*20);
			strcpy(argv[i],a[i]);
		}
		argv[i] = NULL;

		if(strcmp(argv[0],"cd")==0){
			chdir(argv[1]);
		}
		else if(strcmp(argv[0],"exit")==0){
			exit(0);
		}
		else if(strcmp(argv[0],"pwd")==0){
			char work_dir[80];

			getcwd(work_dir,sizeof(work_dir));
			printf("%s\n",work_dir);
		}
		else{
			int pid;
			pid = fork();
			if(pid==0){
				error = execvp(argv[0],argv);
				if(error<0)
					perror("execv");
			}
			wait(NULL);
		}
	}
	return 0;
}	

job4

1. myls.c

myls.c的功能与系统ls程序相同
opendir readdir closedir
在命令行中输入 man opendir 获取帮助
列出指定目录下的文件,例子如下:
$ ./myls job4/test
a
b
c
列出当前目录下的文件,例子如下:
$ cd job4/test
$ ./myls
a
b
c

#include<stdio.h>
#include<dirent.h>
#include<unistd.h>
#include<string.h>

int main(int argc, char *argv[]){
	DIR *dir;
	if(argc >= 2)
		dir = opendir(argv[1]);
	else
		dir = opendir(getcwd(NULL,0));
	while(1){
		struct dirent *de = readdir(dir);
		if(de == NULL)	break;
		if(strcmp(de->d_name,"..")!=0 && strcmp(de->d_name,".")!=0){
					
			printf("%s\n",de->d_name);

		}
	}
	closedir(dir);
	return 0;
}

2. mytree.c

mytree.c的功能与系统tree程序相同
使用空格作为缩进,表示层次
$ ./mytree job4/test
test
 a
 b
 x
 y
 z
c

#include<stdio.h>
#include<dirent.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>

void mytree(int k_num, char *work_dir){
	char k[80] = "";
	for(int i=0;i<k_num;i++)
		strcat(k," ");
	DIR *dir = opendir(work_dir);
	if(dir == NULL){
		perror("opendir");
		exit(0);
	}
	while(1){
		struct dirent *de = readdir(dir);
		if(de == NULL)	break;
		if(strcmp(de->d_name,"..")!=0 && strcmp(de->d_name,".")!=0){
			printf("%s",k);
			printf("%s\n", de->d_name);
			if(de->d_type == DT_DIR){
				strcat(work_dir,"/");
				strcat(work_dir,de->d_name);
				mytree(k_num+1,work_dir);
			}
		}
	}
	closedir(dir);
}


int main(int argc, char *argv[]){
	if(argc >= 2){	
		printf("%s\n",argv[1]);
		mytree(1, argv[1]);
	}
	else{
		printf("%s\n",getcwd(NULL,0));
		mytree(1, getcwd(NULL,0));
	}
	return 0;
}

job5

1.sh2.c

实现shell程序,要求在第1版的基础上,增加文件重定向功能
重定向输入
重定向输出
重定向追加

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>

void child(char *argv[]){
	int num=0;
	int i = 0;
	while(argv[i]){
		i++;
		num++;
	}

	char str1[80];
	char str2[80];
	if(argv[1]!=NULL && argv[1][0] == '<'){
		memcpy(str1, argv[1]+1,sizeof(argv[1]-1));
		int fd1 = open(str1,O_CREAT|O_RDWR,0666);
		dup2(fd1,0);		//input from fd1;
		close(fd1);
		argv[1] = NULL;		//for cat
	}
	if(argv[2]!= NULL && argv[2][0] ==  '>'){
		int fd2;
		if(argv[2][1]=='>'){		// >>
			memcpy(str2,argv[2]+2,sizeof(argv[2]-2));
			fd2 = open(str2,O_CREAT|O_RDWR|O_APPEND,0666);		
		}
		else{				// >	
			memcpy(str2,argv[2]+1,sizeof(argv[2]-1));
			fd2 = open(str2,O_CREAT|O_RDWR|O_TRUNC,0666);
		}
		dup2(fd2,1);	//output into fd2;
		close(fd2);
		argv[2] = NULL;		//for echo
	}

	int error = execvp(argv[0],argv);
	if(error<0)
		perror("execv");
}

int main()
{
	while(1){
		printf("%s","> ");
		char str[105];
		fgets(str,100,stdin);
		int i=0;
		while(str[i]!='\n')
			i++;
		str[i] = '\0';
		
		i=0;
		char a[5][20];
		int num = 0;
		int j=0;
		while(str[i]!='\0')
		{
			if(str[i]!=' '){
				a[num][j++] = str[i];
			}		
			else{
				a[num++][j++] = '\0';
				j=0;
			}
			i++;
		}
		a[num][j++] = '\0';
		int error;
		char *argv[5];
		for(i=0;i<=num;i++){
			argv[i] = (char *)malloc(sizeof(char)*20);
			strcpy(argv[i],a[i]);
		}
		argv[i] = NULL;

		if(strcmp(argv[0],"cd")==0){
			chdir(argv[1]);
		}
		else if(strcmp(argv[0],"exit")==0){
			exit(0);
		}
		else if(strcmp(argv[0],"pwd")==0){
			char work_dir[80];
			getcwd(work_dir,sizeof(work_dir));
			printf("%s\n",work_dir);
		}
		else{
			int pid;
			pid = fork();
			if(pid==0){
				child(argv);
			}
			wait(NULL);
		}
	}
	return 0;
}	

job7

1. pi1.c

使用2个线程根据莱布尼兹级数计算PI

莱布尼兹级数公式: 1 - 1/3 + 1/5 - 1/7 + 1/9 - … = PI/4
主线程创建1个辅助线程
主线程计算级数的前半部分
辅助线程计算级数的后半部分
主线程等待辅助线程运行結束后,将前半部分和后半部分相加

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>

int count = 1e7;

typedef struct{
	double sum;
}result;

void *compute(){
	double sum = 0;
	for(int i=count/2;i<count;i++){
		if(i&1)		//sub
			sum -= (1.0/(i*2+1));
		else 		//sub
			sum += (1.0/(i*2+1));
	}
	result *res;
	res = malloc(sizeof(result));
	res->sum = sum;
	return res;
}

int main(){
	pthread_t compute_tid;
	pthread_create(&compute_tid, NULL, compute, NULL);
	double sum=0;
	for(int i=0;i<count/2;i++){
		if(i&1)		//sub
			sum -= (1.0/(i*2+1));
		else		//add
			sum += (1.0/(i*2+1));
	}
	result *res;
	pthread_join(compute_tid, (void **)&res);	//wait compute finished
	sum = (sum + res->sum)*4;
	printf("%.7lf\n",sum);
	return 0;
}

2. pi2.c

使用N个线程根据莱布尼兹级数计算PI

与上一题类似,但本题更加通用化,能适应N个核心
主线程创建N个辅助线程
每个辅助线程计算一部分任务,并将结果返回
主线程等待N个辅助线程运行结束,将所有辅助线程的结果累加
本题要求 1: 使用线程参数,消除程序中的代码重复
本题要求 2: 不能使用全局变量存储线程返回值

解决思路:
该题主要考查N个线程的创建与运行,首先需要在主线程中创建N个辅助线程,需要通过结构体完成主线程与子线程之间的数值交互,由于需要每个线程完成一部分计算任务,所以需要确定计算的开始和结束位置。主线程等待所有子线程都计算完后将其返回值累加。

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
int N = 4;
int count = 1e7;

typedef struct{		//return the result
	double sum;
}result;

typedef struct{		//connect main_thread and child_thread
	int start;
	int end;
}param;

void *compute(void *arg){
	double sum=0;
	param *par;
	par = (param *)arg;
	for(int i=par->start;i<par->end;i++){
		if(i&1)		//sub
			sum -= (1.0/(i*2+1));
		else		//add
			sum += (1.0/(i*2+1));
	}
	result *res;		// return the result
	res = malloc(sizeof(result));
	res->sum = sum;
	return res;
}

int main(){
	pthread_t computers[N];
	int i;
	param pars[N];
	for(i=0;i<N;i++){		// create the child threads
		param *par;
		par = &pars[i];
		par->start = (count/N) * i;
		par->end = (count/N) * (i+1);
		pthread_create(&computers[i], NULL, compute, par);
	}
	result *res[N];
	for(i=0;i<N;i++)		// wait the child threads
		pthread_join(computers[i], (void**)&res[i]);
	double sum = 0;
	for(i=0;i<N;i++)
		sum += res[i]->sum;		// add the result
	printf("%.7lf\n",sum*4);
	return 0;
}

3. sort.c

多线程排序
主线程创建两个辅助线程
辅助线程1使用选择排序算法对数组的前半部分排序
辅助线程2使用选择排序算法对数组的后半部分排序
主线程等待辅助线程运行結束后,使用归并排序算法归并子线程的计算结果
本题要求 1: 使用线程参数,消除程序中的代码重复

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>

int array[] = {5, 9, 1, 3, 6, 7, 2, 10, 4, 8};
#define N 2
#define num 10
int temp[num];

struct param {
	int *array;
	int start;
	int end;
};

struct result {
	int *array;
};

void *selection_sort(void *arg){
	struct param *param;
	struct result *result;
	int sum = 0;
	param = (struct param *)arg;
	int i,j,min,temp;
	for(i=param->start;i<param->end-1;i++){	
		min = i;
		for(j=i+1;j<param->end;j++){
			if(param->array[j]<param->array[min])
				min = j;
		}
		if(min!=i){
			temp = param->array[min];
			param->array[min] = param->array[i];
			param->array[i] = temp;
		}
	}
	result = malloc(sizeof(struct result));
	result->array = param->array;
	return result;
}

void merge_sort(int a[], int l, int r){
	int mid;
	if( l >= r)	return;
	mid = (l+r)/2;
	merge_sort(a,l,mid);
	merge_sort(a,mid+1,r);
	int i = l, j = mid + 1;
	int k = 0;
	while(i<=mid && j<=r) {
		if(a[i]<=a[j])
			temp[k++] = a[i++];
		else
			temp[k++] = a[j++];
	}
	while(i<=mid) temp[k++] = a[i++];
	while(j<=r) temp[k++] = a[j++];
	for(i=l,j=0;i<=r;i++,j++)
		a[i] = temp[j];
}

int main(){
	pthread_t workers[N];
	struct param params[N];
	for(int i=0;i<N;i++){
		struct param *param;
		param  = &params[i];
		param->array = array;
		param->start = i * (num/N);
	        param->end = (i+1) * (num/N);
		pthread_create(&workers[i], NULL, selection_sort, param);	
	}
	for(int i=0;i<N;i++){
		struct result *result;
		pthread_join(workers[i], (void **)&result);
		free(result);
	}
	// finish selection_sort
	merge_sort(array,0,num-1);
	for(int i=0;i<num;i++)
		printf("%d ",array[i]);
	printf("\n");
	return 0;
}

job8

1. pc.c

使用条件变量解决生产者、计算者、消费者问题

  • 系统中有3个线程:生产者、计算者、消费者
  • 系统中有2个容量为4的缓冲区:buffer1、buffer2
  • 生产者
    • 生产’a’、‘b’、‘c’、‘d’、‘e’、‘f’、‘g’、'h’八个字符
    • 放入到buffer1
    • 打印生产的字符
  • 计算者
    • 从buffer1取出字符
    • 将小写字符转换为大写字符,按照 input:OUTPUT 的格式打印
    • 放入到buffer2
  • 消费者
    • 从buffer2取出字符
    • 打印取出的字符
  • 程序输出结果(实际输出结果是交织的)
    a
    b
    c

    a:A
    b:B
    c:C

    A
    B
    C

解决思路:
此题为课上讲的生产者消费者例子的扩充,等于完成2次生产消费关系。我在第一次做的时候直接将所有的函数及变量都区别了1和2,produce和compute对应为1,compute和consume对应为2,直接照搬课上的例子就可以实现,但是在最后复习的时候搞懂了其中的原理,发现这么写有很多相同的代码片段,一点儿都不简洁,所以用数组和下标实现了相对简洁的代码。
此题首先要创建3个线程,分别代表生产者、计算者、消费者,在生产者中存存数据到第一个buffer里,在计算者中取出生产者存放的数据,并将变化后的结构存入第二个buffer里,在消费者从第二个buffer里取出数据。这里的存取数据中封装了条件变量,实现存取的原子性,减少不必要的控制错误。

#include<stdio.h>
#include<pthread.h>

#define CAPACITY 4
#define ITEM_COUNT (CAPACITY*2)

int buffer1[CAPACITY];
int buffer2[CAPACITY];
int in[2],out[2];

pthread_mutex_t mutex[2];
pthread_cond_t wait_empty_buffer[2];
pthread_cond_t wait_full_buffer[2];

int buffer_is_empty(int i){
	return (in[i]==out[i]);
}

int buffer_is_full(int i){
	return (((in[i]+1)% CAPACITY) == out[i]);
}

void put_item(int i,int item){
	pthread_mutex_lock(&mutex[i]);
	while(buffer_is_full(i))
		pthread_cond_wait(&wait_empty_buffer[i], &mutex[i]);

	if(i==0){				//put item
		buffer1[in[i]] = item;	
	}
	else
		buffer2[in[i]] = item;
	in[i] = (in[i]+1)%CAPACITY;

	pthread_cond_signal(&wait_full_buffer[i]);
	pthread_mutex_unlock(&mutex[i]);
}

int get_item(int i){	
	int item;
	pthread_mutex_lock(&mutex[i]);	 	//let the mutex and cond in the get_item
	while(buffer_is_empty(i))		//prevent some errors
		pthread_cond_wait(&wait_full_buffer[i], &mutex[i]);

	if(i==0)
		item = buffer1[out[i]];		//get item
	else
		item = buffer2[out[i]];

	out[i] = (out[i]+1)% CAPACITY;

	pthread_cond_signal(&wait_empty_buffer[i]);
	pthread_mutex_unlock(&mutex[i]);	
	
	return item;
}

void *produce(){
	int item = 'a';
	for(int i=0;i<ITEM_COUNT;i++){
		printf("%c\n",item);
		put_item(0,item);
		item++;
	}
}

void *compute(){
	int item;
	for(int i=0;i<ITEM_COUNT;i++){
		item = get_item(0);
		printf("    %c:",item);
		item = item - 32;
		put_item(1,item);
		printf("%c\n",item);
	}
}

void *consume(){
	int item;
	for(int i=0;i<ITEM_COUNT;i++){
		item = get_item(1);
		printf("         %c\n",item);
	}
}


int main(){
	pthread_t producer,computer,consumer;

	int i;
	for(i=0;i<2;i++){			//init
		pthread_mutex_init(&mutex[i], NULL);
		pthread_cond_init(&wait_empty_buffer[i], NULL);
		pthread_cond_init(&wait_full_buffer[i], NULL);
	}
	
	//create the sub threads
	pthread_create(&producer, NULL, produce, NULL);		
	pthread_create(&computer, NULL, compute, NULL);
	pthread_create(&consumer, NULL, consume, NULL);

	//wait the sub threads finished
	pthread_join(producer, NULL);
	pthread_join(computer, NULL);
	pthread_join(consumer, NULL);

	return 0;
}

2. pp.c

使用条件变量实现 ping-pong 问题

  • 系统中有2个线程:ping 线程和 pong 线程
  • ping 线程先执行
  • ping 线程执行流程如下
    1. 打印输出 ping
    2. 等待 pong 线程输出
    3. 执行第 1 步
  • pong 线程执行流程如下
    1. 打印输出 pong
    2. 等待 ping 线程输出
    3. 执行第 1 步
  • 程序输出结果
    ping
    pong
    ping
    pong
#include<stdio.h>
#include<pthread.h>

pthread_mutex_t mutex;
pthread_cond_t wait_ping,wait_pong;

int state = 1;

void *ping(){
	int count=0;
	while(count++ < 20){
		pthread_mutex_lock(&mutex);
		while(state!=1)
			pthread_cond_wait(&wait_ping, &mutex);
		printf("ping\n");
		state = 0;
		pthread_cond_signal(&wait_pong);
		pthread_mutex_unlock(&mutex);
	}
}

void *pong(){
	int count=0;
	while(count++ < 20){
		pthread_mutex_lock(&mutex);
		while(state!=0)	
			pthread_cond_wait(&wait_pong, &mutex);
		printf("pong\n");
		state = 1;
		pthread_cond_signal(&wait_ping);
		pthread_mutex_unlock(&mutex);
	}
}

int main(){
	pthread_t ping_tid,pong_tid;
	
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&wait_ping, NULL);
	pthread_cond_init(&wait_pong, NULL);

	pthread_create(&ping_tid, NULL, ping, NULL);
	pthread_create(&pong_tid, NULL, pong, NULL);

	pthread_join(ping_tid, NULL);
	pthread_join(pong_tid, NULL);

	return 0;
}

job9

1. pc.c

使用信号量解决生产者、计算者、消费者问题
功能与 job8/pc.c 相同

解决思路:
使用信号量达到封装的效果,定义信号量的等待和释放函数,等待的过程将信号量的值减一,释放的过程将信号量的值加一,用来判断当前状态是否可用,如果该值小于等于0,那需要一直等待信号量才可以进行下一步操作。
对于此题需要先初始化信号量,创建生产者、计算者、消费者线程。在子线程里,需要先等待信号量,在执行完相应的操作后再释放信号量,允许其它线程进行执行。

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>

#define CAPACITY 4
int buffer1[CAPACITY];
int in1;
int out1;
int buffer2[CAPACITY];
int in2;
int out2;

int buffer1_is_empty(){
	return in1 == out1;
}

int buffer1_is_full(){
	return (in1 + 1) % CAPACITY == out1;
}

int buffer2_is_empty(){
	return in2 == out2;
}

int buffer2_is_full(){
	return (in2 + 1) % CAPACITY == out2;
}

int get_item1(){
	int item1;
	item1 = buffer1[out1];
	out1 = (out1 + 1) % CAPACITY;
	return item1;
}

int get_item2(){
	int item2;
	item2 = buffer2[out2];
	out2 = (out2 + 1) % CAPACITY;
	return item2;
}

void put_item1(int item1){
	buffer1[in1] = item1;
	in1 = (in1 + 1)% CAPACITY;
}

void put_item2(int item2){
	buffer2[in2] = item2;
	in2 = (in2 + 1)% CAPACITY;
}

typedef struct {
	int value;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
} sema_t;

void sema_init(sema_t *sema, int value){
	sema->value = value;
	pthread_mutex_init(&sema->mutex, NULL);
	pthread_cond_init(&sema->cond, NULL);
}

void sema_wait(sema_t *sema){
	pthread_mutex_lock(&sema->mutex);
	while(sema->value <= 0)
		pthread_cond_wait(&sema->cond, &sema->mutex);
	sema->value --;
	pthread_mutex_unlock(&sema->mutex);
}

void sema_signal(sema_t *sema){
	pthread_mutex_lock(&sema->mutex);
	++ sema->value;
	pthread_cond_signal(&sema->cond);
	pthread_mutex_unlock(&sema->mutex);
}

sema_t mutex1_sema;
sema_t empty_buffer1_sema;
sema_t full_buffer1_sema;
sema_t mutex2_sema;
sema_t empty_buffer2_sema;
sema_t full_buffer2_sema;

#define ITEM_COUNT (CAPACITY*2)

void *consume(void *arg){
	int i;
	int item2;
	for(i=0;i<ITEM_COUNT;i++){
		sema_wait(&full_buffer2_sema);
		sema_wait(&mutex2_sema);

		item2 = get_item2();
		printf("        %c\n", item2);

		sema_signal(&mutex2_sema);
		sema_signal(&empty_buffer2_sema);
	}
	return NULL;
}

void *compute(){
	int i;
	int item1;
	int item2;

	for(i=0;i<ITEM_COUNT;i++){
		//read
		sema_wait(&full_buffer1_sema);
		sema_wait(&mutex1_sema);

		item1 = get_item1();
		item2 = item1 - 32;
		printf("    %c:%c\n",item1,item2);

		sema_signal(&mutex1_sema);
		sema_signal(&empty_buffer1_sema);

		//write
		sema_wait(&empty_buffer2_sema);
		sema_wait(&mutex2_sema);

		
		put_item2(item2);
		
		sema_signal(&mutex2_sema);
		sema_signal(&full_buffer2_sema);
	}
	return NULL;
}

void *produce(){
	int i;
	int item1;

	for(i=0;i<ITEM_COUNT;i++){
		sema_wait(&empty_buffer1_sema);
		sema_wait(&mutex1_sema);

		item1 = i + 'a';
		put_item1(item1);
		printf("%c\n", item1);

		sema_signal(&mutex1_sema);
		sema_signal(&full_buffer1_sema);
	}
	return NULL;
}

int main(){
	pthread_t consumer_tid;
	pthread_t computer_tid;

	sema_init(&mutex1_sema,1);
	sema_init(&empty_buffer1_sema, CAPACITY-1);
	sema_init(&full_buffer1_sema, 0);

	sema_init(&mutex2_sema, 1);
	sema_init(&empty_buffer2_sema, CAPACITY-1);
	sema_init(&full_buffer2_sema, 0);

	pthread_create(&computer_tid, NULL, compute, NULL);
	pthread_create(&consumer_tid, NULL, consume, NULL);
	produce();
	pthread_join(consumer_tid, NULL);
	pthread_join(computer_tid, NULL);
	return 0;
}

2. pp.c

使用信号量实现 ping-pong 问题
功能与 job8/pp.c 相同文章来源地址https://www.toymoban.com/news/detail-404504.html

#include<stdio.h>
#include<pthread.h>

#define CAPACITY 4
#define ITEM_COUNT (CAPACITY*2)

int in[2],out[2];
int buffer[2][CAPACITY];

typedef struct{
	int value;
	pthread_mutex_t mutex;
	pthread_cond_t cond;
}sema_t;

void sema_init(sema_t* sema, int value){
	sema->value = value;
	pthread_mutex_init(&sema->mutex, NULL);
	pthread_cond_init(&sema->cond, NULL);
}

void sema_wait(sema_t *sema){
	pthread_mutex_lock(&sema->mutex);
	while(sema->value<=0)
		pthread_cond_wait(&sema->cond, &sema->mutex);
	sema->value--;
	pthread_mutex_unlock(&sema->mutex);
}

void sema_signal(sema_t *sema){
	pthread_mutex_lock(&sema->mutex);
	sema->value++;
	pthread_cond_signal(&sema->cond);
	pthread_mutex_unlock(&sema->mutex);
}

sema_t mutex_sema[2];
sema_t full_buffer[2];
sema_t empty_buffer[2];

int buffer_is_empty(int i){
	return (in[i]==out[i]);
}

int buffer_is_full(int i){
	return ((in[i]+1)%CAPACITY == out[i]);
}

void put_item(int i,int item){
	sema_wait(&mutex_sema[i]);
	sema_wait(&empty_buffer[i]);

	buffer[i][in[i]] = item;
	in[i] = (in[i]+1) % CAPACITY;

	sema_signal(&full_buffer[i]);
	sema_signal(&mutex_sema[i]);
}

int get_item(int i){
	int item;
	sema_wait(&mutex_sema[i]);
	sema_wait(&full_buffer[i]);

	item = buffer[i][out[i]];
	out[i] = (out[i]+1)% CAPACITY;

	sema_signal(&empty_buffer[i]);
	sema_signal(&mutex_sema[i]);

	return item;
}

void *produce(){
	int item = 'a';
	for(int i=0;i<ITEM_COUNT;i++){
		printf("%c\n",item);
		put_item(0,item);
		item++;
	}
}

void *compute(){
	int item;
	for(int i=0;i<ITEM_COUNT;i++){
		item = get_item(0);
		printf("    %c:",item);
		item = item - 32;
		put_item(1, item);
		printf("%c\n", item);
	}
}

void *consume(){
	int item;
	for(int i=0;i<ITEM_COUNT;i++){
		item = get_item(1);
		printf("         %c\n",item);
	}
}

int main(){
	pthread_t producer,computer,consumer;
	int i;
	for(i=0;i<2;i++){
		sema_t *sema;
		sema = &mutex_sema[i];
		sema_init(sema,1);
		sema = &empty_buffer[i];
		sema_init(sema, CAPACITY-1);
		sema = &full_buffer[i];
		sema_init(sema, 0);
	}

	pthread_create(&producer, NULL, produce, NULL);
	pthread_create(&computer, NULL, compute, NULL);
	pthread_create(&consumer, NULL, consume, NULL);

	pthread_join(producer, NULL);
	pthread_join(computer, NULL);
	pthread_join(consumer, NULL);

	return 0;
}

job10

1. sfind.c

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<dirent.h>
#include<sys/stat.h>
#include<unistd.h>

void find_file(char *path, char *target){
	FILE *file = fopen(path, "r");

	char line[256];
	while(fgets(line, sizeof(line), file)){
		if(strstr(line, target))
			printf("%s: %s",path, line);
	}
	fclose(file);
}

void find_dir(char *path, char *target){
	DIR *dir = opendir(path);
	struct dirent *entry;
	while(entry = readdir(dir)){
		char name[256];
		strcpy(name, path);
		if(strcmp(entry->d_name, ".") == 0)
			continue;
		if(strcmp(entry->d_name, "..") == 0)
			continue;
		if(entry->d_type == DT_DIR){
			strcat(name,"/");
			strcat(name,entry->d_name);
	//		printf("%s\n", name);
			find_dir(name, target);
		}
		if(entry->d_type == DT_REG){
			strcat(name,"/");
			strcat(name,entry->d_name);
	//		printf("111%s\n",name);
			find_file(name, target);
		//	printf("file  %s\n", entry->d_name);
		}
	}
	closedir(dir);
}

int main(int argc, char *argv[]){
	if(argc != 3){
		puts("Usage: sfind file string");
		return 0;
	}


	char *path = argv[1];
	char *string = argv[2];


	struct stat info;
	stat(path, &info);

	if(S_ISDIR(info.st_mode))
		find_dir(path, string);
	else
		find_file(path, string);
	return 0;
}

2. pfind.c

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<dirent.h>
#include<sys/stat.h>
#include<unistd.h>
#include<pthread.h>

#define WORKER_NUMBER 4
#define CAPACITY 4

typedef struct{
	int is_end;
	char path[128];
	char string[128];
}task;

task buffer[CAPACITY];
int in;
int out;


int buffer_is_empty(){
	return in==out;
}

int buffer_is_full(){
	return (in+1)%CAPACITY == out;
}

pthread_mutex_t mutex;
pthread_cond_t wait_empty_buffer;
pthread_cond_t wait_full_buffer;

task get_task()
{
	task item;
//	task *buffer;
//	buffer = &buffer[out];
	pthread_mutex_lock(&mutex);
	while(buffer_is_empty())
		pthread_cond_wait(&wait_full_buffer, &mutex);

	item.is_end = buffer[out].is_end;
	strcpy(item.path,buffer[out].path);
	strcpy(item.string, buffer[out].string);
	out = (out + 1) % CAPACITY;

	pthread_cond_signal(&wait_empty_buffer);
	pthread_mutex_unlock(&mutex);
	
	return item;
}

void put_task(task *item){
//	task *buffer;
//	buffer = &buffer[in];
	pthread_mutex_lock(&mutex);
	while(buffer_is_full())
		pthread_cond_wait(&wait_empty_buffer, &mutex);

	buffer[in].is_end = item->is_end;
	strcpy(buffer[in].path, item->path);
	strcpy(buffer[in].string, item->string);
	in = (in + 1) % CAPACITY;

	pthread_cond_signal(&wait_full_buffer);
	pthread_mutex_unlock(&mutex);
}

void find_file(char *path, char *target){
	FILE *file = fopen(path, "r");

	char line[256];
	while(fgets(line, sizeof(line), file)){
		if(strstr(line, target))
			printf("%s: %s",path, line);
	}
	fclose(file);
}

void *worker_entry(){
	while(1){
		task t;
		t = get_task();
		if(t.is_end)
			break;
		find_file(t.path, t.string);
	}
	return NULL;
}
void find_dir(char *path, char *target){
	DIR *dir = opendir(path);
	struct dirent *entry;
	while(entry = readdir(dir)){
		char name[256];
		strcpy(name, path);
		if(strcmp(entry->d_name, ".") == 0)
			continue;
		if(strcmp(entry->d_name, "..") == 0)
			continue;
		if(entry->d_type == DT_DIR){
			strcat(name,"/");
			strcat(name,entry->d_name);
		//	printf("%s\n", name);
			find_dir(name, target);
		}
		if(entry->d_type == DT_REG){
			strcat(name,"/");
			strcat(name,entry->d_name);
			task item;
			item.is_end = 0;
			strcpy(item.path, name);
			strcpy(item.string, target);
			put_task(&item);
		}
	}
	closedir(dir);
}

int main(int argc, char *argv[]){
	if(argc != 3){
		puts("Usage: sfind file string");
		return 0;
	}


	char *path = argv[1];
	char *string = argv[2];

	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&wait_empty_buffer, NULL);
	pthread_cond_init(&wait_full_buffer, NULL);


	struct stat info;
	stat(path, &info);

	pthread_t workers[WORKER_NUMBER];
	for(int i=0;i<WORKER_NUMBER;i++){
		pthread_create(&workers[i], NULL, worker_entry, NULL);
	}


	if(S_ISDIR(info.st_mode)){
		find_dir(path, string);
		for(int i=0;i<WORKER_NUMBER;i++){
			task item;
			item.is_end = 1;
			put_task(&item);
		}
	}
	else
		find_file(path, string);
	for(int i=0;i<WORKER_NUMBER;i++){
		pthread_join(workers[i], NULL);
	}
	return 0;
}

到了这里,关于NUAA操作系统OS实验及上机考试记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • windows虚拟机安装Mac OS系统(操作图解)

    因为工作需要学习ios开发,但是苹果电脑申请了还没审批下来所以想着先搭建一个虚拟机来熟悉开发环境 安装环境 windows,vmware 16 Pro 一、准备工作         1.  vmware 16 Pro 下载          2. unlocker  下载地址,选择zip下载          3. macos12.6 (链接:https://pan.baidu

    2024年02月16日
    浏览(47)
  • 汽车电子笔记之:AUTOSA架构下的多核OS操作系统

    目录 1、AUTOSAR多核操作系统 1.1、OS Application 1.2、多核OS的软件分区 1.3、任务调度 1.4、核间任务同步 1.5、计数器、报警器、调度表 1.6、自旋锁与共享资源 1.7、核间通信IOC 1.8、OS Object中元素交互 1.9、多核OS的启动与关闭 2、多核OS注意事项 2.1、最小部署单元 2.2、核间通信及影

    2024年02月11日
    浏览(44)
  • Linux 操作系统(Cent OS虚拟机)——DHCP的安装与配置

    本次使用的虚拟机是CentOS 64位 的 一、安装DHCP服务器软件 1.配置网络环境 VMware Workstation 软件 上方工具栏选择编辑→虚拟网络编辑器,  自己的电脑上需要先点击“更改设置”,授予权限,如下图,如果没有这个选项则说明已经有权限,跳过这一步到下一步。  如果你的电脑

    2024年02月07日
    浏览(52)
  • 【Java】【OS】操作系统理发店问题通过应用小程序动态实现(1)

    He/she will spend a random time on the chair before send the ready flag to the barber. */ public synchronized void sitBarberChair(BarberShopApplet applet, int id) { while(customerSofaQ[sofaBottom] != id) { System.out.println(\\\"Customer \\\" + id + “is waiting for the chair turn”); try{ wait(); } catch(InterruptedException e) { } } while(chairFull()) { try {

    2024年04月23日
    浏览(52)
  • 【Linux OS】华为openEuler操作系统与openGauss数据库安装及使用入门

    EulerOS 是华为自主研发的服务器操作系统,支持六种处理器架构:x86,Arm,RISC—V,LoongArch,SW64和Power,能够满足客户从传统IT基础设施到云计算服务的需求。 openEuler是EulerOS的开源社区版本。 官网OS镜像下载地址:https://www.openeuler.org/zh/download/ 推荐下载LTS版,当前最新版为:

    2024年02月08日
    浏览(47)
  • 【操作系统OS】学习笔记:第二章 进程与线程 (上)【哈工大李治军老师】

    基于本人观看学习 哈工大李治军老师主讲的操作系统课程 所做的笔记,仅进行交流分享 特此鸣谢李治军老师,操作系统的神作! 如果本篇笔记帮助到了你,还请点赞 关注 支持一下 ♡𖥦)!! 主页专栏有更多,如有疑问欢迎大家指正讨论,共同进步! 给大家跳段街舞感谢支持

    2024年02月02日
    浏览(59)
  • 操作系统考试复习——第三章 预防死锁 避免死锁

    预防死锁: 就是破坏死锁产生的四个条件之一就行。 0.破坏互斥条件:由于互斥条件是非共享设备所必须的所以,不仅不能改变还需要保证。因此我们主要考虑剩下的三个条件。 1. 破坏 \\\"请求和保持\\\" 条件 请求和保持也就是系统已经请求了一个资源它现在占有这个资源但是它

    2024年02月03日
    浏览(44)
  • 嵌入式系统设计师考试笔记之操作系统基础复习笔记二

    目录 3、任务管理 (1)嵌入式操作系统的任务管理可以分为 (2)进程 (3)线程 (4)任务 (5)任务的创建与中止 (6)任务的状态任务有三中基本状态: (7)任务控制块 TCB (8)任务的切换 (9)任务的调度 (10)实时系统调度 (11)任务互斥 (12)信号量 (13)任务同

    2024年02月08日
    浏览(55)
  • 云计算专业期末RHEL8.6红帽网络操作系统考试(实操)

    本文介绍关于云计算专业期末RHEL8.6红帽操作系统考试内容题目详解 一般情况下虚拟机中的系统是已经安装好的,但以防万一还是加上在虚拟机中系统安装的步骤 (后缀为.iso的为镜像文件,下图这些文件都为iso镜像文件) (这里所填的用户名和密码在接下来登录中需要使用

    2024年01月22日
    浏览(47)
  • 操作系统考试复习——第四章 存储器管理 4.1 4.2

    存储器的层次结构: 存储器的多层结构: 存储器至少分为三级:CPU寄存器,主存和辅存。 但是 一般分为6层 为寄存器,高速缓存,主存储器,磁盘缓存,固定磁盘,可移动存储介质。 这几个部分是 速度依次减小 但是 存储容量是依次增大 的。  只有固定磁盘和可移动存储

    2024年02月03日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包