操作系统实验二、典型同步问题模拟处理编程设计与实现

一、实验目的

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

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

二、实验内容

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

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

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

1.由fork创建的新进程被称为子进程。该函数被调用一次,但返回两次。所以先创建一个子进程,然后在父进程中再创建一个子进程,通过输出的内容观察fork函数的用法

2.1生产者-消费者问题

生产者、消费者共享一个初始为空、大小为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。

四、结果分析

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

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

image-20211114201848580

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

image-20211114201819186

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

image-20211114201748194

五、源程序

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

2.1

# 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(6);
        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(3);
        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

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

/*
* 	写者优先
*/

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

Logo

更多推荐