OS实验二【典型同步问题模拟处理编程设计与实现】

一、实验目的

1、加深对进程概念的理解,明确进程和程序的区别。

2、探索、理解并掌握操作系统同步机制的应用编程方法,针对典型的同步问题,构建基于Windows(或 Linux)操作系统同步机制的解决方案。

二、实验内容

1、熟悉和运用 Linux操作系统中系统调用fork()的功能,编写程序调用fork()创建两个子进程。父进程显示字符串‘Parent:’;两个子进程分别显示字符串‘Child1:’和‘Child2:’。多次运行此程序,观察屏幕显示的结果,并分析原因。

2、了解、熟悉和运用 Windows(或 Linux)操作系统同步机制及编程方法,针对典型的同步问题,譬如生产者-消费者问题读者优先的读者-写者问题写者优先的读者-写者问题读者数限定的读者-写者问题哲学家就餐问题(任选一至二个),编程模拟实现相应问题的解决方案。

三、设计原理(或方案)及相关算法

操作系统实验二、典型同步问题模拟处理编程设计与实现https://blog.csdn.net/m0_48958478/article/details/1222367061.由fork创建的新进程被称为子进程。该函数被调用一次,但返回两次。所以先创建一个子进程,然后在父进程中再创建一个子进程,通过输出的内容观察fork函数的用法。

2.1生产者-消费者问题

生产者-消费者问题详解http://blog.chinaunix.net/uid-21411227-id-1826740.html生产者、消费者共享一个初始为空、大小为n的缓冲区。
只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。只有缓冲区不空时,消费者才能从中取出产品,否则必须等待。缓冲区是临界资源,各进程必须互斥地访问。

2.2读者优先的读者写者问题

读者优先指的是除非有写者在写文件,否则读者不需要等待。所以可以用一个整型变量read_count记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当read_count=O时,表明所有的读者读完,需要释放写者等待队列中的一个写者)。每一个读者开始读文件时,必须修改read_count变量。因此需要一个互斥对象mutex来实现对全局变量read_count修改时的互斥.另外,为了实现写-写互斥,需要增加一个临界区对象write。当写者发出写请求时,必须申请临界区对象的所有权。通过这种方法,也可以实现读-写互斥,当read_count=1时(即第一个读者到来时),读者线程也必须申请临界区对象的所有权。当读者拥有临界区的所有权时,写者阻塞在临界区对象write上。当写者拥有临界区的所有权时,第一个读者判断完"read_count==1"后阻塞在write上,其余的读者由于等待对read_count的判断,阻塞在mutex上。

2.3写者优先的读者写者问题

写者优先与读者优先类似。不同之处在于一旦一个写者到来,它应该尽快对文件进行写操作,如果有一个写者在等待,则新到来的读者不允许进行读操作。为此应当添加一个整型变量write_count,用于记录正在等待的写者的数目,当write_count=O时,才可以释放等待的读者线程队列。为了对全局变量write_count实现互斥,必须增加一个互斥对象mutex2。为了实现写者优先,应当添加一个临界区对象read,当有写者在写文件或等待时,读者必须阻塞在read上。同样,有读者读时,写者必须等待。于是,必须有一个互斥对象RW_mutex来实现这个互斥。有写者在写时,写者必须等待。读者线程要对全局变量read_count实现操作上的互斥,必须有一个互斥对象命名为mutex1。

2.4哲学家就餐问题

由Dijkstra提出并解决的哲学家进餐问题(The Dinning Philosophers Problem)是典型的同步问题。该问题是描述有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五只筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐完毕,放下筷子继续思考。

四、结果分析

编译程序加不加 -lpthread 的区别https://www.cnblogs.com/sky-heaven/p/6840693.htmlgcc编译线程程序,为什么要加-lpthread,头文件已经包含了了啊

包含头文件了,仅能说明有了线程函数的声明, 但是还没有实现, 加上-lpthread是在链接阶段,链接这个库

-lpthread -lm 这两个参数在多线程中起到什么作用? -pthread和-lpthread有什么区别?

lpthread是表示要连接到pthread的库是这里省略的lib,你应该可以找到共享库libpthread.so的。因为pthread编程用到的函数在pthread库里面,就像你使用pow等数学计算函数,需要用到math.h.需要 -lm。

Linux进程创建及同步实验(fork()函数使用,生产者-消费者问题的p,v操作)https://blog.csdn.net/qq_38898129/article/details/808272801.从实验结果可以体现出fork()进程被调用一次但返回两次

2.1缓冲区为空时,生产者生产产品。当缓冲区有产品时,消费者消费产品。输入q结束进程

2.2写者线程先到达,开始运行,之后读者线程到达,对文件资源进行P操作,写者线程进入阻塞状态,读者 线程开始运行。

2.3读者线程运行时,写者线程到达,因为写者优先,所以读者进程进入阻塞状态,写者线程运行。

哲学家就餐问题C语言实现(涉及多线程、信号量等)https://blog.csdn.net/qq_44806305/article/details/1068819252.4本程序用五个线程模拟五位哲学家,用五个sem_t型信号量模拟五根筷子(临界资源),解题的思想是:每次让每位哲学家优先拿起自己左边的筷子,并限制最多有四个人同时拿起筷子,从而避免了死锁情况,该程序模拟五个哲学家进餐一次的情况,并重复模拟了1000次以上来检验是否出现死锁情况,经检验程序运行正常,没有出现死锁状况,此处图片仅展示了第1000次的情况。

五、源程序

 1.从实验结果可以体现出fork()进程被调用一次但返回两次

    vim fork.c

#include <stdio.h>
#include <stdlib.h>
int main(){
    int p1,p2;
    //由fork创建的新进程被称为子进程( child process)。该函数被调用一次,但返回两次。
    //两次返回的区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID
    while((p1=fork())==-1);
    if (p1==0)
        printf("Child1 \n");
    else
        {
          while((p2=fork())==-1);
          if (p2==0)
            printf("Child2 \n");
          else
            printf("Parent \n"); 
        }
    return 0;  
}

Linux进程创建及同步实验(fork()函数使用,生产者-消费者问题的p,v操作)https://blog.csdn.net/qq_38898129/article/details/80827280

    vim fork2.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
 
 
int main(int argc,char *argv[])
{
	pid_t pid1,pid2;        //进程标识符
	pid1 = fork();     //创建一个新的进程
	if(pid1<0)
	{
		printf("创建进程失败!");
		exit(1);
	}
	else if(pid1==0)   //如果pid为0则表示当前执行的是子进程
	{
		printf("子进程1,进程标识符是%d\n",getpid());
	}
	else          //否则为父进程
	{
		pid2 = fork();//創建一個新的進
		if(pid2<0)
		{
			printf("创建进程失败!");
			exit(1);
		}
		else if(pid2==0)   //如果pid为0则表示当前执行的是子进程
		{
			printf("子进程2,进程标识符是%d\n",getpid());
		}
		else          //否则为父进程
		{
			printf("父进程,进程标识符是%d\n",getpid());
		}
	}
	return 0;
}

这里的pid_t类似一个类型,就像int型一样,int型定义的变量都是整型的,pid_t定义的类型都是进程号类型。这个语句的意思是定义了一个pid_t类型的变量pid,fork()函数返回一个进程号,这个进程号赋给了pid。

2.1缓冲区为空时,生产者生产产品。当缓冲区有产品时,消费者消费产品。输入q结束进程 

    vim pc.c 

# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>
#define BUFFER_SIZE 5

//empty  同步信号量,表示剩余空间的数量
// full 同步信号量,表示产品的数量
// mutex 互斥信号量,实现对缓冲区的互斥访问
sem_t empty, full, mutex;

typedef int buffer_item;

//缓冲区
buffer_item buffer[BUFFER_SIZE];

int in, out;

// 记录产品的id
int id = 0;

//生产产品
int insert_item(buffer_item item) {
    buffer[out] = item;
    out = (out + 1) % BUFFER_SIZE;
    return 0;
}

//消费产品
int remove_item(buffer_item *item) {
    // 将buffer[in]移除,并将item填充进去
    *item = buffer[in];
    in = (in + 1) % BUFFER_SIZE;
    return 0;
}

//生产者
void *producer(void* param) {
    long threadid = (long)param;
    while (1){
        sem_wait(&empty);
        sem_wait(&mutex);
        //生产产品
        insert_item(id);
        sleep(2);
        printf("ThreadId %ld : Producer produce product %d \n", threadid,id);
        id++;
        sem_post(&mutex);
        sem_post(&full);
    }
}

//消费者
void *consumer(void* param) {
    long threadid = (long)param;
    while (1){
        sem_wait(&full);
        sem_wait(&mutex);
        //消费产品
        int item;
        remove_item(&item);
        sleep(1);
        printf("ThreadId %ld : Consumer consume product %d \n", threadid ,item);
        sem_post(&mutex);
        sem_post(&empty);
    }
}

int main() {
    //线程id
    pthread_t tid[4];
    //对mutex进行初始化
    //第二个参数 不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享
    //第三个参数 给出了信号量的初始值。  
    sem_init(&mutex, 0, 1);
    sem_init(&empty, 0, BUFFER_SIZE);
    sem_init(&full, 0, 0);
    in = out = 0;
    //两个生产者,两个消费者
    pthread_create(&tid[0], NULL ,consumer, (void*)0);
    pthread_create(&tid[1], NULL ,producer, (void*)1);
    pthread_create(&tid[2], NULL ,consumer, (void*)2);
    pthread_create(&tid[3], NULL, producer, (void*)3);
    int c=0;
    while (1){
        c = getchar();
        //用户输入q,结束进程,否则继续运行
        if (c=='q' || c=='Q'){
            for (int i = 0; i < 4; ++i) {
                pthread_cancel(tid[i]);
            }
            break;
        }
    }
    //释放信号量
    sem_destroy(&mutex);
    sem_destroy(&empty);
    sem_destroy(&full);
    return 0;
}

2.2写者线程先到达,开始运行,之后读者线程到达,对文件资源进行P操作,写者线程进入阻塞状态,读者 线程开始运行。

    vim Readerfirst.c 

/*
* 	读者优先
*/

# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>

// wrt(记录型信号量) 用于实现对文件的互斥访问
// mutex 用于对count变量的互斥访问
sem_t wrt, mutex;
//记录当前有几个读进程在访问文件
int readCount;


//读者
void* Reader(void* param) {
    long threadid = (long)param;
    while (1){
        // P操作,各进程互斥地访问 mutex
        sem_wait(&mutex);
        readCount++;
        if(readCount == 1)
            sem_wait(&wrt);
        //  V操作
        sem_post(&mutex);
        printf("Thread %ld: is reading\n", threadid);
        sleep(0.3);
        sem_wait(&mutex);
        readCount--;
        if(readCount == 0)
            sem_post(&wrt);
        sem_post(&mutex);
    }
}

//写者
void* Writer(void* param) {
    long threadid = (long)param;
    while (1){
        sem_wait(&wrt);
        printf("Thread %ld: is writing\n", threadid);
        sleep(0.5);
        sem_post(&wrt);
    }
}
int main() {
    sem_init(&mutex, 0, 1);
    sem_init(&wrt, 0, 1);
    readCount = 0;
    pthread_t tid[4];
    //两个写者,两个读者
    pthread_create(&tid[0], NULL ,Writer, (void*)0);
    pthread_create(&tid[1], NULL, Writer, (void*)1);
    pthread_create(&tid[2], NULL ,Reader, (void*)2);
    pthread_create(&tid[3], NULL ,Reader, (void*)3);
    int c=0;
    while(1){
         c=getchar();
        //用户输入q,结束进程,否则继续运行
        if (c=='q' || c=='Q'){
            for (int i = 0; i < 4; ++i) {
                pthread_cancel(tid[i]);
            }
            break;
        }
    }

    //信号量销毁
    sem_destroy(&mutex);
    sem_destroy(&wrt);
    return 0;
}


2.3读者线程运行时,写者线程到达,因为写者优先,所以读者进程进入阻塞状态,写者线程运

    vim Writerfirst.c  

/*
* 	写者优先
*/
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>

// RWMutex 读写互斥
// mutex1 readCount互斥
// mutex2 writeCount互斥
// wrt 写者互斥
// mutex3的主要用处就是避免写者同时与多个读者进行竞争,读者中信号量RWMutex比mutex3先释放,则一旦有写者,写者可马上获得资源。
sem_t RWMutex, mutex1, mutex2, mutex3, wrt;
//用于记录正在等待的写者的数目
int writeCount, readCount;


//读者
void* Reader(void* param) {
    long threadid = (long)param;
    while (1){
        //p操作
        sem_wait(&mutex3);
        sem_wait(&RWMutex);
        sem_wait(&mutex2);
        readCount++;
        if(readCount == 1)
            sem_wait(&wrt);
        //v操作
        sem_post(&mutex2);
        sem_post(&RWMutex);
        sem_post(&mutex3);
        sleep(0.3);
        printf("Thread %ld: is reading\n", threadid);
        sem_wait(&mutex2);
        readCount--;
        if(readCount == 0)
            sem_post(&wrt);
        sem_post(&mutex2);
    }
}

//写者
void* Writer(void* param) {
    long threadid = (long)param;
    while (1){
        sem_wait(&mutex1);
        writeCount++;
        if(writeCount == 1){
            sem_wait(&RWMutex);
        }
        sem_post(&mutex1);
        sem_wait(&wrt);
        sleep(0.5);
        printf("Thread %ld: is writing\n", threadid );
        sem_post(&wrt);
        sem_wait(&mutex1);
        writeCount--;
        if(writeCount == 0) {
            sem_post(&RWMutex);
        }
        sem_post(&mutex1);
    }
}

int main() {
    sem_init(&mutex1, 0, 1);
    sem_init(&mutex2, 0, 1);
    sem_init(&mutex3, 0, 1);
    sem_init(&wrt, 0, 1);
    sem_init(&RWMutex, 0, 1);
    readCount = writeCount = 0;
    pthread_t tid[4];
    //两个写者,两个读者
    pthread_create(&tid[0], NULL ,Reader, (void*)2);
    pthread_create(&tid[1], NULL ,Reader, (void*)3);    
    pthread_create(&tid[2], NULL ,Writer, (void*)0);
    pthread_create(&tid[3], NULL, Writer, (void*)1);
    int c=0;
    while(1){
            c=getchar();
            //用户输入q,结束进程,否则继续运行
            if (c=='q' || c=='Q'){
                for (int i = 0; i < 4; ++i) {
                    pthread_cancel(tid[i]);
                }
                break;
            }
        }

    sem_destroy(&mutex1);
    sem_destroy(&mutex2);
    sem_destroy(&mutex3);
    sem_destroy(&RWMutex);
    sem_destroy(&wrt);
    return 0;
}

2.4本程序用五个线程模拟五位哲学家,用五个sem_t型信号量模拟五根筷子(临界资源),解题的思想是:每次让每位哲学家优先拿起自己左边的筷子,并限制最多有四个人同时拿起筷子,从而避免了死锁情况,该程序模拟五个哲学家进餐一次的情况,并重复模拟了1000次以上来检验是否出现死锁情况,经检验程序运行正常,没有出现死锁状况,此处图片仅展示了第1000次的情况。

    vim Philosophers.c   

#include <unistd.h>
#include "pthread.h"
#include "stdio.h"
#include "stdlib.h"
#include "semaphore.h"

#define NUM 5
int ID[NUM]={0,1,2,3,4};
sem_t sem_chopsticks[NUM];
sem_t sem_eaters;
int eaters_num=0;
void sem_signal_init(){
    int i;
    for (i=0; i<NUM; i++){
        if (sem_init(&sem_chopsticks[i],0,1) == -1){
            perror("oops:em_init error!");
            exit(1);
        }
    }
    if (sem_init(&sem_eaters,0,NUM-1) == -1){
        perror("oops:em_init error!");
        exit(1);
    }
}

void philosopher(void * ptid){
    int pthread_id = *(int *)ptid%NUM;
    printf("%d philosopher is thinking...\n",(int)pthread_id);
    sem_wait(&sem_eaters);
    sem_wait(&sem_chopsticks[pthread_id]);
    printf("%d philosopher takes chopstick %d...\n",(int)pthread_id,(int)pthread_id);
    sem_wait(&sem_chopsticks[(pthread_id+1)%NUM]);
    printf("%d philosopher takes chopstick %d...\n",(int)pthread_id,((int)pthread_id+1)%NUM);
    printf("%d philosopher is eating, %d philosopher had already dined.\n",(int)pthread_id,eaters_num);
    sem_post(&sem_chopsticks[(pthread_id+1)%NUM]);
    sem_post(&sem_chopsticks[pthread_id]);
    sem_post(&sem_eaters);
    eaters_num++;
    printf("%d philosopher had dined, by now %d philosopher had already dined.\n",(int)pthread_id,eaters_num);

}

int main(){
    int i,l,j,k;
    for (l = 0; l < 1000; ++l) {
        printf("**********************%d times try ******************************",l+1);
        pthread_t philosopher_threads[NUM];
        sem_signal_init();
        for ( i= 0; i < NUM; i++) {
            printf("%d times\n",i);
            if (pthread_create(&philosopher_threads[i], NULL, (void *)&philosopher,&ID[i]) != 0){
                perror("oops:pthread_create error!");
                exit(1);
            }
        }

        for ( j = 0; j < NUM; j++) {
            pthread_join(philosopher_threads[j], NULL);
        }
        sem_destroy(&sem_eaters);
        for (k = 0; k < NUM ; ++k) {
            sem_destroy(&sem_chopsticks[k]);
        }
        eaters_num = 0;
//        sleep(2);
    }

    return 0;
}

模拟进程管理 #include <stdio.h> #include <malloc.h> //Can only be used in independent situation; //#define getmem(type) (type*)malloc(sizeof(type)) #define buffersize 5 int processnum=0;//the num of processes struct pcb { /* 定义进程控制块PCB */ int flag;//flag=1 denote producer;flag=2 denote consumer; int numlabel; char product; char state; struct pcb* processlink; }*exe=NULL,*over=NULL; typedef struct pcb PCB; PCB* readyhead=NULL,* readytail=NULL; PCB* consumerhead=NULL,* consumertail=NULL; PCB* producerhead=NULL,* producertail=NULL; //产品数量 int productnum=0; int full=0,empty=buffersize;// semaphore char buffer[buffersize];//缓冲区 int bufferpoint=0;//缓冲区指针 void linkqueue(PCB* process,PCB** tail); PCB* getq(PCB* head,PCB** tail); bool hasElement(PCB* pro); void display(PCB* p); void linklist(PCB* p,PCB* listhead); void freelink(PCB* linkhead); bool processproc(); bool waitempty(); bool waitfull(); void signalempty(); void signalfull(); void producerrun(); void comsuerrun(); bool hasElement(PCB* pro); void linklist(PCB* p,PCB* listhead) { PCB* cursor=listhead; while(cursor->processlink!=NULL){ cursor=cursor->processlink; } cursor->processlink=p; } void freelink(PCB* linkhead) { PCB* p; while(linkhead!=NULL){ p=linkhead; linkhead=linkhead->processlink; free(p); } } void linkqueue(PCB* process,PCB** tail) { if((*tail)!=NULL){ (*tail)->processlink=process; (*tail)=process; } else{ printf("队列未初始化!"); } } PCB* getq(PCB* head,PCB** tail) { PCB* p; p=head->processlink; if(p!=NULL){ head->processlink=p->processlink; p->processlink=NULL; if( head->processlink ==NULL ) (*tail)=head; } else return NULL; return p; } bool processproc() { int i,f,num; char ch; PCB* p=NULL; PCB** p1=NULL; printf("\n 请输入希望产生的进程个数?"); scanf("%d",&num); getchar(); // if(num>=100){ // printf("您怎么要产生这么多进程!Demands Denied!"); // return false; // } for(i=0;i<num;i++){ printf("\n 请输入您要产生的进程:输入1为生产者进程;输入2为消费者进程\n"); scanf("%d",&f); getchar(); p=(PCB*)malloc(sizeof(PCB)) ; if( !p) { printf("内存分配失败"); return false; } p->flag=f; processnum++; p->numlabel=processnum; p->state='w'; p->processlink=NULL; if(p->flag==1){ printf("您要产生的进程是生产者,它是第%d个进程。请您输入您要该进程产生的字符!\n",processnum); scanf("%c",&ch); getchar(); p->product=ch; productnum++; printf("您要该进程产生的字符是%c \n",p->product); } else { printf("您要产生的进程是消费者,它是第%d个进程。\n",p->numlabel); } linkqueue(p,&readytail); } return true; } bool waitempty() { if(empty<=0) { printf("进程%d:缓冲区存数,缓冲区满,该进程进入生产者等待队列\n",exe->numlabel); linkqueue(exe,&producertail); return false; } else{ empty--; return true; } } void signalempty() { PCB* p; if(hasElement(producerhead)){ p=getq(producerhead,&producertail); linkqueue(p,&readytail); printf("等待中的生产者进程进入就绪队列,它的进程号是%d\n",p->numlabel); } empty++; } bool waitfull() { if(full<=0) { printf("进程%d:缓冲区取数,缓冲区空,该进程进入消费者等待队列\n",exe->numlabel); linkqueue(exe,&consumertail); return false; } else{ full--; return true;} } void signalfull() { PCB* p; if(hasElement(consumerhead)){ p=getq(consumerhead,&consumertail); linkqueue(p,&readytail); printf("等待中的消费者进程进入就绪队列,它的进程号是%d\n",p->numlabel); } full++; } void producerrun() { if(!waitempty()) return; printf("进程%d开始向缓冲区存数%c\n",exe->numlabel,exe->product); buffer[bufferpoint]=exe->product; bufferpoint++; printf("进程%d向缓冲区存数操作结束\n",exe->numlabel); signalfull(); linklist(exe,over); } void comsuerrun() { if(!waitfull()) return; printf("进程%d开始向缓冲区取数\n",exe->numlabel); exe->product=buffer[bufferpoint-1]; bufferpoint--; printf("进程%d向缓冲区取数操作结束,取数是%c\n",exe->numlabel,exe->product); signalempty(); linklist(exe,over); } void display(PCB* p) { p=p->processlink; while(p!=NULL){ printf("进程%d,它是一个",p->numlabel); p->flag==1? printf("生产者\n"):printf("消费者\n"); p=p->processlink; } } bool hasElement(PCB* pro) { if(pro->processlink==NULL) return false; else return true; } void main() { char terminate; bool element; printf("你想开始程序吗?(y/n)"); scanf("%c",&terminate); getchar(); //Queue initialize; readyhead=(PCB*)malloc(sizeof(PCB)); if(readyhead==NULL) return; readytail=readyhead; readyhead->flag=3; readyhead->numlabel=processnum; readyhead->state='w'; readyhead->processlink=NULL; consumerhead=(PCB*)malloc(sizeof(PCB)); if(consumerhead==NULL) return; consumertail=consumerhead; consumerhead->processlink=NULL; consumerhead->flag=4; consumerhead->numlabel=processnum; consumerhead->state='w'; consumerhead->processlink=NULL; producerhead=(PCB*)malloc(sizeof(PCB)); if(producerhead==NULL) return; producertail=producerhead; producerhead->processlink=NULL; producerhead->flag=5; producerhead->numlabel=processnum; producerhead->state='w'; producerhead->processlink=NULL; over=(PCB*)malloc(sizeof(PCB)); if(over==NULL) return; over->processlink=NULL; while(terminate=='y') { if(!processproc()) break; element=hasElement(readyhead); while(element){ exe=getq(readyhead,&readytail); printf("进程%d申请运行,它是一个",exe->numlabel); exe->flag==1? printf("生产者\n"):printf("消费者\n"); if(exe->flag==1) producerrun(); else comsuerrun(); element=hasElement(readyhead); } printf("就绪队列没有进程\n"); if(hasElement(consumerhead)) { printf("消费者等待队列中有进程:\n"); display(consumerhead); } else { printf("消费者等待队列中没有进程\n"); } if(hasElement(producerhead)) { printf("生产者等待队列中有进程:\n"); display(producerhead); } else { printf("生产者等待队列中没有进程\n"); } printf("你想继续吗?(press 'y' for on)"); scanf("%c",&terminate); getchar(); } printf("\n\n 进程模拟完成.\n"); //Free the room; freelink(over); over=NULL; freelink(readyhead); readyhead=NULL; readytail=NULL; freelink(consumerhead); consumerhead=NULL; consumertail=NULL; freelink(producerhead); producerhead=NULL; producertail=NULL; getchar(); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

书启秋枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值