NUAA操作系统实验报告

操作系统实验报告

1.mysys.c

题目要求

实现函数mysys,用于执行一个系统命令,要求如下

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

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

解决思路

​ 将输入的命令存储在字符串str内,之后传入mysys函数,mysys函数首先判断命令是否合法,如果是空的,则输出error,反之,fork产生子进程,也就是表示pid的变量p为0时,即当前进程为子进程,然后在子进程中完成execl函数的调用,去执行字符串传入的命令,父进程等待子进程完成后退出mysys函数。

实验代码

#include
#include
#include
#include
void mysys(char *str)
{
	pid_t p;
	if(str != NULL){
		p = fork();
		if(p == 0){
			execl("/bin/sh","sh","-c",str,NULL);		
		}
		wait(NULL);
	}
	else
	{
		printf("error\n");
		exit(0);
	}
}
int  main()
{
    printf("-----------------------------\n");
    mysys("echo HELLO WORLD");
    printf("-----------------------------\n");
    mysys("ls /");
    return 0;
}

运行结果

shiyanlou:~/ $ cc mysys.c -o mysys                                 
shiyanlou:~/ $ ./mysys 
--------------------------------------------------
HELLO WORLD
--------------------------------------------------
anaconda3   boot  dev   home   lib64   mnt   proc   run   srv   tmp   var
bin         data  etc   lib    media   opt   root   sbin  sys   usr
--------------------------------------------------

2.sh3.c

题目要求

实现shell程序,要求在第2版的基础上,添加如下功能

  • 实现管道
  • 只要求连接两个命令,不要求连接多个命令
  • 不要求同时处理管道和重定向
# 执行sh3
$ ./sh3

# 执行命令cat和wc,使用管道连接cat和wc
> cat /etc/passwd | wc -l
  • 考虑如何实现管道和文件重定向,暂不做强制要求
$ cat input.txt
3
2
1
3
2
1
$ cat output.txt
$ cat output.txt
1
2
3

解决思路

对于管道:

  • 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。

  • 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。

  • 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。

​ 代码思路:首先读取一行指令,进入exec函数执行指令,对指令进行划分判断,根据字符串的不同情况,判断命令参数和重定向内容,运用execl函数执行不同的逻辑操作。在对字符串进行判断时,碰到 ‘>’ 时处理输出重定向,下一单词为output,碰到 ‘<’ 的下一单词为输入重定向,下一单词为input。

实验代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUFLEN 1024
#define RE_NO 0
#define RE_OUT 1
#define RE_IN 2
#define RE_ALL 3
int getLine(char *buffer, int length) {
    char c;
    int count = 0;
    c = getchar();
    while (c != '\n') {
        count++;
        if (count < length - 1) {
            buffer[count - 1] = c;
        } else return 0;
        c = getchar();
    }
    buffer[count] = '\0';
    return 1;
}
void clearBuf(char *buffer, int length) {
    for (int i = 0; i < length; i++) buffer[i] = '\0';
}
int redirctYN(char *str) {
    int lef = 0;
    int rig = 0;
    for (int i = 0; i < strlen(str); i++) {
        if (str[i] == '<') lef = 1;
        if (str[i] == '>') rig = 1;
    }
    if (!lef && rig) return RE_OUT;
    if (lef && !rig) return RE_IN;
    if (lef && rig) return RE_ALL;
    return RE_NO;
}
void exec(char *str) {
    char buffer[BUFLEN];
    char str2[BUFLEN];
    strcpy(str2, str);
    char path[BUFLEN];
    char *p = NULL;
    char *name = NULL;
    int fd;
    pid_t pid;
    if (strcmp(str, "")) {
        int type = redirctYN(str);
        switch (type) {
            case RE_NO:
                strcpy(buffer, str);
                p = strtok(buffer, " ");
                if (p) {
                    if (!strcmp(p, "cd")) {
                        p = strtok(NULL, "");
                        if (chdir(p) < 0) printf("error\n");
                    } else if (!strcmp(p, "pwd")) {
                        getcwd(path, BUFLEN);
                        printf("%s\n", path);
                    } else if (!strcmp(p, "exit")) {
                        exit(0);
                    } else {
                        mysys(str);
                    }
                }
                break;
            case RE_ALL:
            case RE_OUT:
                name = outRedDeal(str2);
                if (name) {
                    pid = fork();
                    if (pid == 0) {
                        fd = open(name, O_CREAT | O_RDWR, 0666);
                        dup2(fd, 1);
                        close(fd);
                        exec(str2);
                        exit(0);
                    } else waitpid(pid, NULL, 0);
                }
                break;
            case RE_IN:
                name = inRedDeal(str2);
                if (name) {
                    pid = fork();
                    if (pid == 0) {
                        fd = open(name, O_CREAT | O_RDWR, 0666);
                        dup2(fd, 0);
                        close(fd);
                        exec(str2);
                        exit(0);
                    } else waitpid(pid, NULL, 0);
                }
                break;
        }
    }
}
char *outRedDeal(char *str) {
    char *name = (char *) malloc(sizeof(char) * BUFLEN);
    int end;

    int symbol = getIndex(str, '>');
    if (symbol < 0 || symbol == strlen(str) - 1) return NULL;

    if (str[symbol + 1] == ' ') {
        end = symbol + 2;
        for (int i = symbol + 2; i < strlen(str); i++) {
            if (str[i] == ' ') break;
            end++;
        }
        strncpy(name, &str[symbol + 2], end - (symbol + 2));
        delStr(str, symbol, end);
    } else {
        end = symbol + 1;
        for (int i = symbol + 1; i < strlen(str); i++) {
            if (str[i] == ' ') break;
            end++;
        }
        strncpy(name, &str[symbol + 1], end - (symbol + 1));
        delStr(str, symbol, end);
    }
    return name;
}
char *inRedDeal(char *str) {
    char *name = (char *) malloc(sizeof(char) * BUFLEN);
    int end;
    int symbol = getIndex(str, '<');
    if (symbol < 0 || symbol == strlen(str) - 1) return NULL;
    if (str[symbol + 1] == ' ') {
        end = symbol + 2;
        for (int i = symbol + 2; i < strlen(str); i++) {
            if (str[i] == ' ') break;
            end++;
        }
        strncpy(name, &str[symbol + 2], end - (symbol + 2));
        delStr(str, symbol, end);
    } else {
        end = symbol + 1;
        for (int i = symbol + 1; i < strlen(str); i++) {
            if (str[i] == ' ') break;
            end++;
        }
        strncpy(name, &str[symbol + 1], end - (symbol + 1));
        delStr(str, symbol, end);
    }
    return name;
}
void delStr(char *str, int start, int end) {
    int length = end - start;
    if (length > 0) {
        for (int i = start; i < strlen(str) - 1; i++) str[i] = str[i + 1];
        str[strlen(str) - 1] = '\0';
        delStr(str, start, end - 1);
    }
}
int getIndex(char *str, char c) {
    int symbol = -1;
    int i, j, end;
    char *name = (char *) malloc(sizeof(char) * BUFLEN);
    for (i = 0; i < strlen(str); i++) {
        if (str[i] == c) {
            symbol = i;
            break;
        }
    }
    return symbol;
}
int mysys(char *arg) {
    pid_t fpid = fork();
    if (fpid < 0) {
        return -1;
    } else if (fpid == 0) {
        if (execl("/bin/sh", "sh", "-c", arg, (char *) 0) < 0) {
            return 127;
        }
    } else {
        waitpid(fpid, NULL, 0);
        return 0;
    }
    return 0;
}
char *Split(char *str, int location) {
    str[location] = '\0';
    return &str[location + 1];
}
int main(int argc, char *argv[]) {
    char buffer[BUFLEN];
    while (1) {
        printf(">");
        clearBuf(buffer, BUFLEN);
        if (getLine(buffer, BUFLEN)) {
            exec(buffer);
        } else {
            printf("input error\n");
        }
    }
    return 0;
}

运行结果

shiyanlou:~/ $ cc sh3.c -o sh3                                     
shiyanlou:~/ $ ./sh3                                            
>cat /etc/passwd | wc -l
36
>cat input.txt
1 2 3 5 4 3
>cat output.txt
>cat output.txt
1 2 3 5 4 3

3.pi1.c

题目要求

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

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

解决思路

​ 使用两个线程去计算莱布尼兹级数公式,主线程计算前半部分,辅助线程计算后半部分,最后计算得到的结果为PI/4,将其进行输出。工作线程执行函数worker计算级数的前半段(0n/2+1),主线程执行函数master计算级数的后半段(n/2+1n-1),pthread_join等待子线程结束,得到结果,主函数内total是二者值的和,为最后结果。

​ 本题中n为变量NUMBER,将它定义为150000,计算结果,得到结果PI/4=0.785397,PI = 4×0.785397 = 3.141588,结果正确。当NUMBER越大,得到的结果也就约精确,当然程序耗时也会更长。

实验代码

#include 
#include 
#include 
#define NUMBER 150000
float worker_output=0;
void *worker(void *arg)
{
    int i;
    float w;
    for (i = 0; i < NUMBER / 2+1; i++)
        {
        	w=1.0/(i*2 + 1);
        	for(int j=0;j<i;j++)
        		w=-1*w;
        	worker_output +=w;
		}
    return NULL;
}
float master_output=0;
void master()
{
    int i;
    float m;
    for (i = NUMBER / 2+1; i < NUMBER; i++)
    {
    	m=1.0/(i*2 + 1);
    	for(int j=0;j<i;j++)
    		m=-1*m;
    	master_output += m;
	} 
}
int main()
{ 
    pthread_t worker_tid;
    float total;
    pthread_create(&worker_tid, NULL, worker, NULL);
    master(); 
    pthread_join(worker_tid, NULL);
    total = master_output + worker_output;
    printf(" PI/4 = %f\n", total);
    return 0;
}

运行结果

shiyanlou:~/ $ cc pi1.c -o pi1 -lpthread                                 
shiyanlou:~/ $ ./pi1
PI/4 = 0.785397

4.pi2.c

题目要求

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

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

解决思路

​ NR_CPU代表线程数,结构体param用来传参,之后利用线程参数传递每个部分的起始值和结束值,每个线程负责NR_TOTAL/NR_CPU长度的计算,结构体result储存线程返回值。

​ 在主线程内开启NR_CPU个线程,每个辅助线程调用compute函数计算对应的的值,利用pthread_join函数接收线程入口返回值result,之后累加得到PI/4。本题中取n为500000,线程数为10,计算结果为0.785398,为PI/4的近似值。

实验代码

#include 
#include 
#include 

#define NR_TOTAL 500000
#define NR_CPU 10
#define NR_CHILD (NR_TOTAL/NR_CPU)

struct param {
    int start;   //起始值
    int end;     //结束值
};

struct result {
    float sum;   //线程返回值
};

void *compute(void *arg)
{
    struct param *param;
    struct result *result;
    float sum = 0;
    int i;
    param = (struct param *)arg;
    for (i = param->start; i < param->end; i++)
        if(i%2)
        sum -= 1.0/(i*2+1);
        else
        sum += 1.0/(i*2+1);
    result = malloc(sizeof(struct result));
    result->sum = sum;
    return result;
}

int main()
{ 
    pthread_t workers[NR_CPU];
    struct param params[NR_CPU]; 
    int i;
    for (i = 0; i < NR_CPU; i++) {
        struct param *param;
        param = &params[i];
        param->start = i * NR_CHILD; 
        param->end = (i + 1) * NR_CHILD;
        pthread_create(&workers[i], NULL, compute, param);
    }
    float sum = 0;
    for (i = 0; i < NR_CPU; i++) {
        struct result *result;
        pthread_join(workers[i], (void **)&result);
        sum += result->sum;
        free(result);
    }

    printf("PI/4 = %f\n", sum);
    return 0;
}

运行结果

shiyanlou:~/ $ cc pi2.c -o pi2 -lpthread                                 
shiyanlou:~/ $ ./pi2       
PI/4 = 0.785398

5.pc1.c

题目要求

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

  • 系统中有3个线程:生产者、计算者、消费者
  • 系统中有2个容量为4的缓冲区:buffer1、buffer2
  • 生产者生产’a’、‘b’、‘c’、‘d’、‘e’、‘f’、‘g’、'h’八个字符,放入到buffer1
  • 计算者从buffer1取出字符,将小写字符转换为大写字符,放入到buffer2
  • 消费者从buffer2取出字符,将其打印到屏幕上

解决思路

总共有三个角色,他们的关系是:计算者相当于生产者的消费者,“消费者”相当于计算者的消费者。

​ 1.生产者产生字符后,查看buffer1的锁状态,加锁,之后判断buffer1是否为满,满则阻塞等待,反之放入缓冲区buffer1,之后唤醒等待的计算者线程,解开锁。

​ 2.计算者被唤醒后,获取buffer1的锁,加锁,判断buffer1是否为空,如果空则阻塞等待,反之取出一个字符,转化为大写形式。之后再唤醒生产者,释放锁。接下来,它作为消费者的生产者,查看buffer2的锁状态,加锁,之后判断buffer2是否为满,满则阻塞等待,反之将字符放入缓冲区buffer2,之后唤醒等待的消费者线程,解开锁。

​ 3.消费者被唤醒后,获取buffer2的锁,加锁,判断buffer2是否为空,如果空则阻塞等待,反之取出一个字符,输出到屏幕上,之后唤醒消费者,解开锁。

以上三个进程以此往复,进行工作,产生的结果每次可能是不一样的,因为进程的执行顺序未知。

  • buffer1_in、buffer1_out、buffer2_in、buffer2_out四个变量定义两个缓冲区的读写指针,通过他们来存取字符。
  • mutex1、mutex2为两个缓冲区的锁。同时还有几个判断缓冲区状态的函数和存取字符的函数。

实验代码

#include 
#include 
#include 

#define CAPACITY 4
int buffer1[CAPACITY];
int buffer2[CAPACITY];
int buffer1_in;
int buffer1_out;
int buffer2_in;
int buffer2_out;

void buffer_init()
{
    buffer1_in = 0;
    buffer1_out = 0;
    buffer2_in = 0;
    buffer2_out = 0;
}
int buffer1_is_empty()
{
    return buffer1_in == buffer1_out;
}

int buffer1_is_full()
{
    return (buffer1_in + 1) % CAPACITY == buffer1_out;
}

int buffer2_is_empty()
{
    return buffer2_in == buffer2_out;
}

int buffer2_is_full()
{
    return (buffer2_in + 1) % CAPACITY == buffer2_out;
}
int get_buffer1_item()
{
    int item;

    item = buffer1[buffer1_out];
    buffer1_out = (buffer1_out + 1) % CAPACITY;
    return item;
}

void put_buffer1_item(int item)
{
    buffer1[buffer1_in] = item;
    buffer1_in = (buffer1_in + 1) % CAPACITY;
}

int get_buffer2_item()
{
    int item;

    item = buffer2[buffer2_out];
    buffer2_out = (buffer2_out + 1) % CAPACITY;
    return item;
}

void put_buffer2_item(int item)
{
    buffer2[buffer2_in] = item;
    buffer2_in = (buffer2_in + 1) % CAPACITY;
}

pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
pthread_cond_t wait_empty_buffer1;
pthread_cond_t wait_full_buffer1;
pthread_cond_t wait_empty_buffer2;
pthread_cond_t wait_full_buffer2;

#define ITEM_COUNT (CAPACITY * 2)

void *produce(void *arg)
{
    int i;
    int item;
    for (i = 0; i < ITEM_COUNT; i++) { 
        pthread_mutex_lock(&mutex1);
        while (buffer1_is_full())
            pthread_cond_wait(&wait_empty_buffer1, &mutex1);
        item = 'a'+i;
        put_buffer1_item(item); 
        printf("     produce : %c\n", item); 
        pthread_cond_signal(&wait_full_buffer1);
        pthread_mutex_unlock(&mutex1);
    }
    return NULL;
}
void *count(void *arg)
{
	int i;
	int item;
	for(i = 0; i < ITEM_COUNT; i++)
	{
		pthread_mutex_lock(&mutex1);
		while(buffer1_is_empty())
			pthread_cond_wait(&wait_full_buffer1, &mutex1);
		item=get_buffer1_item()-32;		
		pthread_cond_signal(&wait_empty_buffer1);
		pthread_mutex_unlock(&mutex1);		
		pthread_mutex_lock(&mutex2);
		while(buffer2_is_full())
			pthread_cond_wait(&wait_empty_buffer2, &mutex2);			
		put_buffer2_item(item);	
		pthread_cond_signal(&wait_full_buffer2);
		pthread_mutex_unlock(&mutex2);	
	}
	return NULL;
}
void *consume(void *arg)
{
    int i;
    int item;
    for (i = 0; i < ITEM_COUNT; i++) { 
        pthread_mutex_lock(&mutex2);
        while (buffer2_is_empty()) 
            pthread_cond_wait(&wait_full_buffer2, &mutex2);
        item = get_buffer2_item();
        printf("consume : %c\n", item); 
        pthread_cond_signal(&wait_empty_buffer2);
        pthread_mutex_unlock(&mutex2);
    }
    return NULL;
}
int main()
{
    pthread_t producer;
    pthread_t counter;
    pthread_t consumer;

    buffer_init();
    pthread_create(&producer, NULL, produce, NULL);
    pthread_create(&producer, NULL, count, NULL);
    pthread_create(&consumer, NULL, consume, NULL);

    pthread_join(producer, NULL);
    pthread_join(counter, NULL);
    pthread_join(consumer, NULL);
    return 0;
}

运行结果

shiyanlou:~/ $ cc pc1.c -o pc1 -lpthread                                   
shiyanlou:~/ $ ./pc1                                              
    produce item: a
    produce item: b
    produce item: c
    produce item: d
    produce item: e
consume item: A
consume item: B
consume item: C
    produce item: f
consume item: D
consume item: E
    produce item: g
consume item: F
    produce item: h
consume item: G
consume item: H

6.pc2.c

题目要求

使用信号量解决生产者、计算者、消费者问题

  • 功能和前面的实验相同,使用信号量解决

解决思路

总共有三个角色,他们的关系是:计算者相当于生产者的消费者,“消费者”相当于计算者的消费者,按一定的逻辑执行PV操作。

​ 1.生产者首先执行sema_wait(&empty_buffer_sema1) 函数,访问buffer1的空闲位置。当有空闲位置时, empty_buffer_sema1减1,对buffer1加锁,加入字符后解开锁。再执行sema_signal(&full__buffer_sema1)函数,full_buffer_semal加1,唤起计算者进程。

​ 2.计算者首先执行sema_wait(&full_buffer_sema1) 函数,判断buffer1是否有值,如果等到有值的情况,则full_buffer_sema1减1,加buffer1的锁,取字符转换为大写形式,解开锁,再执行(&empty_buffer_sema1),此时empty_buffer_sema1加1,唤醒等待的生产者线程。之后作为生产者,向buffer2写字符,首先执行sema_wait(&full_buffer_sema2) 函数,判断是否buffer2有值,如果等到有值的情况,则full_buffer_sema2减1,加buffer1的锁,取字符转换为大写形式,解开锁,再执行(&empty_buffer_sema2),此时empty_buffer_sema2加1,唤醒等待的消费者线程。

​ 3.消费者首先执行sema_wait(&full_buffer_sema2) ,判断是否buffer2有值,如果有值,则full_buffer_sema2减1,加buffer2的锁,取字符打印输出,解开锁,再执行sema_signal(&empty_buffer_sema2),此时empty__buffer_sema2加1,唤醒等待的计算者线程。

  • mutex_sema1,mutex_sema2是buffer1,buffer2的锁。读写变量同上。
  • empty_buffer_sema1,empty_buffer_sema2表示缓冲区空位个数,full_buffer_sema1,full_buffer_sema2表示已经存放的字符个数。

实验代码

#include 
#include 
#include 

#define CAPACITY 4
int buffer1[CAPACITY];
int buffer2[CAPACITY];
int buffer1_in;
int buffer1_out;
int buffer2_in;
int buffer2_out;

void buffer_init()
{
    buffer1_in = 0;
    buffer1_out = 0;
    buffer2_in = 0;
    buffer2_out = 0;
}

int buffer1_is_empty()
{
    return buffer1_in == buffer1_out;
}

int buffer1_is_full()
{
    return (buffer1_in + 1) % CAPACITY == buffer1_out;
}

int buffer2_is_empty()
{
    return buffer2_in == buffer2_out;
}

int buffer2_is_full()
{
    return (buffer2_in + 1) % CAPACITY == buffer2_out;
}

int get_buffer1_item()
{
    int item;
    item = buffer1[buffer1_out];
    buffer1_out = (buffer1_out + 1) % CAPACITY;
    return item;
}

void put_buffer1_item(int item)
{
    buffer1[buffer1_in] = item;
    buffer1_in = (buffer1_in + 1) % CAPACITY;
}

int get_buffer2_item()
{
    int item;
    item = buffer2[buffer2_out];
    buffer2_out = (buffer2_out + 1) % CAPACITY;
    return item;
}

void put_buffer2_item(int item)
{
    buffer2[buffer2_in] = item;
    buffer2_in = (buffer2_in + 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 mutex_sema1;
sema_t empty_buffer_sema1;
sema_t full_buffer_sema1;
sema_t mutex_sema2;
sema_t empty_buffer_sema2;
sema_t full_buffer_sema2;
#define ITEM_COUNT (CAPACITY * 2)

void *produce(void *arg)
{
    int i;
    int item;
    for (i = 0; i < ITEM_COUNT; i++) { 
        sema_wait(&empty_buffer_sema1);
        sema_wait(&mutex_sema1);
        item = 'a'+i;
        put_buffer1_item(item); 
        printf("      produce item: %c\n", item); 
        sema_signal(&mutex_sema1);
        sema_signal(&full_buffer_sema1);
    }
    return NULL;
}
void *count(void *arg)
{
	int i;
	int item;
	for(i = 0; i < ITEM_COUNT; i++)
	{
        sema_wait(&full_buffer_sema1);
        sema_wait(&mutex_sema1);	
        
        item=get_buffer1_item()-32;
        
        sema_signal(&mutex_sema1);
        sema_signal(&empty_buffer_sema1);
        
        sema_wait(&empty_buffer_sema2);
        sema_wait(&mutex_sema2);
        
        put_buffer2_item(item);
        
        sema_signal(&mutex_sema2);
        sema_signal(&full_buffer_sema2);	
	}
	return NULL;
}
void *consume(void *arg)
{
    int i;
    int item;
    for (i = 0; i < ITEM_COUNT; i++) { 
        sema_wait(&full_buffer_sema2);
        sema_wait(&mutex_sema2);

        item = get_buffer2_item();
        printf("consume item: %c\n", item); 

        sema_signal(&mutex_sema2);
        sema_signal(&empty_buffer_sema2);
    }
    return NULL;
}
int main()
{
    pthread_t producer;
    pthread_t counter;
    pthread_t consumer;
    sema_init(&mutex_sema1, 1);
    sema_init(&empty_buffer_sema1, CAPACITY - 1);
    sema_init(&full_buffer_sema1, 0);
    sema_init(&mutex_sema2, 1);
    sema_init(&empty_buffer_sema2, CAPACITY - 1);
    sema_init(&full_buffer_sema2, 0);
    
    pthread_create(&producer, NULL, produce, NULL);
    pthread_create(&producer, NULL, count, NULL);
    pthread_create(&consumer, NULL, consume, NULL);

    pthread_join(producer, NULL);
    pthread_join(counter, NULL);
    pthread_join(consumer, NULL);
    return 0;
}

运行结果

shiyanlou:~/ $ cc pc2.c -o pc2 -lpthread                                   
shiyanlou:~/ $ ./pc2   
    produce item: a
    produce item: b
    produce item: c
consume item: A
consume item: B
consume item: C
    produce item: d
    produce item: e
    produce item: f
consume item: D
consume item: E
consume item: F
    produce item: g
    produce item: h
consume item: G
consume item: H

你可能感兴趣的:(经验分享,linux)