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 相同

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值