记录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 = ¶ms[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 线程执行流程如下
- 打印输出 ping
- 等待 pong 线程输出
- 执行第 1 步
- pong 线程执行流程如下
- 打印输出 pong
- 等待 ping 线程输出
- 执行第 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;
}