操作系统实验三:同步问题

本次实验涉及操作系统中的同步问题,包括进程上下文切换、互斥执行、信号量机制等。通过创建四个进程实现特定执行顺序,模拟售票与退票系统确保结果正确,以及生产者消费者模型保证输入输出同步。实验还探讨了共享内存、管道和消息队列的同步机制,并研究了Pintos操作系统的进程切换流程。

实验三:同步问题

在Linux系统中的实现
系统调用的进一步理解
进程上下文切换
同步的方法

实验内容

  1. 通过fork的方式,产生4个进程P1,P2,P3,P4,每个进程打印输出自己的名字,例如P1输出“I am the process P1”。要求P1最先执行,P2、P3互斥执行,P4最后执行。通过多次测试验证实现是否正确。
  2. 火车票余票数ticketCount 初始值为1000,有一个售票线程,一个退票线程,各循环执行多次。添加同步机制,使得结果始终正确。要求多次测试添加同步机制前后的实验效果。(说明:为了更容易产生并发错误,可以在适当的位置增加一些pthread_yield(),放弃CPU,并强制线程频繁切换,例如售票线程的关键代码:
    temp=ticketCount;
    pthread_yield();
    temp=temp-1;
    pthread_yield();
    ticketCount=temp;
    退票线程的关键代码:
    temp=ticketCount;
    pthread_yield();
    temp=temp+1;
    pthread_yield();
    ticketCount=temp;
  3. 一个生产者一个消费者线程同步。设置一个线程共享的缓冲区, char buf[10]。一个线程不断从键盘输入字符到buf,一个线程不断的把buf的内容输出到显示器。要求输出的和输入的字符和顺序完全一致。(在输出线程中,每次输出睡眠一秒钟,然后以不同的速度输入测试输出是否正确)。要求多次测试添加同步机制前后的实验效果。
  4. 进程通信问题。阅读并运行共享内存、管道、消息队列三种机制的代码。
    ​ a)通过实验测试,验证共享内存的代码中,receiver能否正确读出sender发送的字符串?如果把其中互斥的代码删除,观察实验结果有何不同?如果在发送和接收进程中打印输出共享内存地址,他们是否相同,为什么?
    ​ b)有名管道和无名管道通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?
    ​ c)消息通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?
  5. 阅读Pintos操作系统,找到并阅读进程上下文切换的代码,说明实现的保存和恢复的上下文内容以及进程切换的工作流程。

Task1

通过fork的方式,产生4个进程P1,P2,P3,P4,每个进程打印输出自己的名字,例如P1输出“I am the process P1”。要求P1最先执行,P2、P3互斥执行,P4最后执行。通过多次测试验证实现是否正确。

实验代码

请见如下代码及注释

#include<sys/types.h> 
#include<unistd.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<pthread.h> 
#include <fcntl.h> 
#include <sys/stat.h> 
#include <semaphore.h>    
sem_t* mySem_2 = NULL;
sem_t* mySem_3 = NULL;
sem_t* mySem_23 = NULL;
   
int main(){
   
   
    pid_t pid_1,pid_root;
    mySem_2 = sem_open("P2", O_CREAT, 0666, 0);
    mySem_3 = sem_open("P3", O_CREAT, 0666, 0);
    mySem_23 = sem_open("P23", O_CREAT, 0666, 0);
   
    pid_root = getpid();
    for(int i = 0; i<= 1; i++){
   
   
        pid_1 = fork();
        if (i==0) {
   
   
            if (pid_1 > 0){
   
   
                // root father             
                }
            else if (pid_1 == 0)
            {
   
   
                // P1             
                }
            else
            {
   
   
                // error                 
                perror("fork!\n");
            }
        } else
        {
   
   
            if (pid_1 > 0)
            {
   
   
                if(getpid() == pid_root)
                {
   
   
                    // root father                 
                    } else
                {
   
   
                    pid_1 = fork();
                    if(pid_1 == 0){
   
   
                        // P4                         
                        sem_wait(mySem_2);//等待p2信号量
                        sem_wait(mySem_3);//等待p3信号量
                        printf("I am the process P4\n");
                    } else
                    {
   
   
                        // P1                         
                        printf("I am the process P1\n");
                        sem_post(mySem_23);//解开互斥锁
                    }                
                }
            } else if (pid_1 == 0)
            {
   
   
                if(getppid()!=pid_root){
   
   
                    // P3                     
                    sem_wait(mySem_23);//p3进程使用,锁上23之间互斥锁
                    printf("I am the process P3\n");
                    sem_post(mySem_23);
                    sem_post(mySem_3);
                } else
                {
   
   
                    // P2                     
                    sleep(1);                     
                    sem_wait(mySem_23);//p2进程使用,锁上23之间互斥锁
                    printf("I am the process P2\n");
                    sem_post(mySem_23);
                    sem_post(mySem_2);
                }
            } else
            {
   
   
                // error                 
                perror("fork!");
            }
        }
    }
    int i = 10;
    while(i--){
   
   
        sleep(1);
    }
    //销毁信号量
    sem_close(mySem_2);
    sem_close(mySem_3);
    sem_close(mySem_23);
    sem_unlink("P2");
    sem_unlink("P3");
    sem_unlink("P23");
    return 0;
}

实验结果

在这里插入图片描述
在这里插入图片描述
进程树如下图所示:
在这里插入图片描述
建立2,3信号量以满足p4进程在2,3均完成之后才执行。23信号量是一把互斥锁,保障p2和p3进程互斥执行。

Task2

火车票余票数ticketCount 初始值为1000,有一个售票线程,一个退票线程,各循环执行多次。添加同步机制,使得结果始终正确。要求多次测试添加同步机制前后的实验效果。

实验代码

请见如下代码及注释

#include<sys/types.h> 
#include<unistd.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<pthread.h> 
#include <fcntl.h> 
#include <sys/stat.h> 
#include <semaphore.h> 
#include <sched.h> 
sem_t* mySem = NULL;
int tickets = 1000;//全局变量
void*sold(){
   
   
    int i = 100;
    while(i--){
   
   
        sem_wait(mySem); //互斥锁 上锁
        printf("Current tickes number is %d.\n",tickets);
        int temp = tickets;        
        temp = temp - 1;       
        tickets = temp;
        sem_post(mySem);  //互斥锁 解锁 }
}
void*returnT(){
   
   
    int i = 100;
    while(i--){
   
   
        sem_wait(mySem);   //互斥锁  上锁   
        printf("Current tickes number is %d.\n",tickets);
        int temp = tickets;
        temp = temp + 1;        
        tickets = temp;
        sem_post(mySem);  //互斥锁 解锁 }
}
int 
图书馆登记和注销 要求:有一阅览室,读者进入时必须先在一张登记表上登记。该表中每个表项代表阅览室中的一个座位。读者离开时要消掉其登记信息。阅览室共有50 个座位。登记表每次仅允许一位读者进行登记或注销。 本实验由两个进程组成,分别是登陆和注销进程 使用到的函数和信号量 HANDLE mutex; HANDLE empty; HANDLE full; 创建信号量 HANDLE CreateSemaphore( __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,// lpSemaphoreAttributes是信号量的安全属性 可为NULL __in LONG lInitialCount,// lInitialCount是初始化的信号量 __in LONG lMaximumCount,// lMaximumCount是允许信号量增加到最大值 __in_opt LPCWSTR lpName//lpName是信号量的名称 可为NULL ); 创建互斥信号量 HANDLE CreateMutex(  LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针 可为NULL  BOOL bInitialOwner, // 初始化互斥对象的所有者  LPCTSTR lpName // 指向互斥对象名的指针 ); 申请一个资源 WaitForSingleObject(HANDLE full,INFINITE); 释放资源 ReleaseSemaphore( __in HANDLE hSemaphore,// hSemaphore是要增加的信号量句柄 __in LONG lReleaseCount,// lReleaseCount是增加的计数。 __out_opt LPLONG lpPreviousCount//lpPreviousCount是增加前的数值返回。 ); 释放互斥信号量 BOOL ReleaseMutex(HANDLE hMutex); DWORD WaitForMultipleObjects( DWORD nCount, // number of handles in array CONST HANDLE *lpHandles, // object-handle array BOOL bWaitAll, // wait option DWORD dwMilliseconds // time-out interval );
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值