精华内容
下载资源
问答
  • 操作系统实践报告

    2018-07-04 17:57:50
    1.1.2进程与线程的区别答:进程与线程是相互联系又是有区别的(1)一个进程包含多个线程,所以说它们之间是相互联系的(2)调度性:在传统操作系统中,进程是独立运行,调度,资源分配的基本单位,而在线程操作系统...

    1 线程的创建与启动

    1.1 进程与线程

    1.1.1什么是线程

    答:线程是独立运行,调度的基本单位。

    1.1.2进程与线程的区别

    答:进程与线程是相互联系又是有区别的

    (1)一个进程包含多个线程,所以说它们之间是相互联系的

    (2)调度性:在传统操作系统中,进程是独立运行,调度,资源分配的基本单位,而在线程操作系统中,线程是调度,独立运行的基本单位,而进程是资源分配的基本单位。

    (3)并发性:进程和线程都可以并发执行

    (4)资源性;进程不管在传统os还是线程的os中都是资源分配的基本单位,线程不能实现资源的分配

    1.2 Java中的Thread和Runnable类

    1.2.1 Java中创建多线程

    答:一个Thread类的对象对应一个线程,创建一个Runnable接口的对象并使用Thread对象启动它,Thread t= new Thread (obj)(obj代表Runnable的对象),用start()函数启动线程。

    1.3 三种创建线程的办法

    1.3.1实验方法一:

    package org.yang;

    /**

     * Runnable的实现类,是线程执行的主体。

     * run函数是入口

     *

     */

    class MyR implementsRunnable{

       private String msg;

       public MyR(String msg) {

          this.msg = msg;

       }

       //线程的入口

       @Override

       publicvoid run() {

          while(true) {

             try {          

                System.out.println(msg);

                Thread.sleep(1000);

             }catch(InterruptedException e) {

                e.printStackTrace();

                break;

             }

          }

       }

    }

    publicclassTestThread {

    publicstaticvoidmain(String[] args){

          //创建了线程

          Threadthread1= newThread(newMyR("hello"));

          thread1.start(); //启动了线程

          Threadthread2= newThread(newMyR("wuwu"));

          thread2.start(); //启动了线程

       }

    }

    1.3.2实验方法二

    package org.yang;

    publicclassTestThread2 {

    publicstaticvoidmain(String[] args){

          TestThread2testThread2=newTestThread2();

          //匿名信  匿名类   引用就是指针

          Runnablerunnable= newRunnable() {

             @Override

             publicvoid run() {

                while(true) {

                    try {          

                       System.out.println("haha");

                       Thread.sleep(1000);

                    }catch(InterruptedException e) {

                       e.printStackTrace();

                       break;

                    }

                }

             }

          };

          Threadthread= newThread(runnable);

          thread.start();

       }

    }

    1.3.3实验方法三

    package org.yang;

    publicclassTestThread3 {

    publicstaticvoidmain(String[] args){

          new Thread(new Runnable() {

             @Override

             publicvoid run() {

                System.out.println("haha");

             }

          }).start();

          // lamda 表达式 java 1.8+

          new Thread(()->{

             System.out.println("haha");      

          }).start();

       }

    }

    2 线程简单同步(同步块)

    2.1 同步的概念和必要性

    2.1.1同步的定义

    答:两个进程使用同一资源时,一个进程必须停下来等待另一个进程完成后才能使用这一资源。

    2.1.2必要性

    答:保证进程之间互斥的使用资源,没有同步机制会导致资源不合理利用。

    2.2 synchronize关键字和同步块

    2.2.1synchronize关键字:在多线程环境下的应用synchronized 关键字,它包括两种用法:synchronized 方法和 synchr onized synchronized方法。synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。

    2.2.2同步块:同步块用来标记方法或者代码块是同步的。Java同步块用来避免竞争。

    2.3 实例

    关键字实验:

    package org.yang;

    import java.util.ArrayList;

    publicclassTestSync {

       staticint  c = 0;

       static Object lock = new Object(); //(1) 随便建立了一个变量,作为锁变量

       publicstaticvoid main(String[] args) {

          Thread[]threads= newThread[1000];

          for(inti=0;i<1000;i++) {

             finalintindex = i//(4) 建立了一个final变量,放半在lamba中使用

             threads[i] = new Thread(()->{

             synchronized (lock) { //(2) 创建一个同步块,需要一个锁。

          System.out.println("thread "+index+"enter");//5)输出

                    inta  = c//获取c的值

                    a++; //将值加一

                    try {//模拟复杂处理过程

                       Thread.sleep((long) (Math.random()*10));

                    }catch(InterruptedException e) {

                       // TODO Auto-generated catch block

                       e.printStackTrace();

                    }

                    c=a; //存回去

                    System.out.println("thread "+index+"leave");//(6)输出

                }//3这是块的终结

             });

             threads[i].start(); //线程开始

          }

          for(inti=0;i<1000;i++) {

             try {

                threads[i].join(); //等待 thread i 完成

             }catch(InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

             }

          }//循环后,所有的线程都完成了

          System.out.print("c="+c); //输出c的结果

       }

    }

     

    3 生产者消费者问题

    3.1 问题表述

    生产者消费者问题(Producer-consumer problem),也称有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程--即所谓的"生产者"和"消费者"--在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。

    该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

    3.2 实现思路

    要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

    3.3 Java实现该问题的代码

    3.3.1 Queue队列代码:

    packageorg.yang;

    importjava.util.LinkedList;

    importjava.util.concurrent.locks.Condition;

    importjava.util.concurrent.locks.Lock;

    importjava.util.concurrent.locks.ReentrantLock;

     

    publicclass Queue { //队列

      

       private Lock lock =new ReentrantLook();  //锁

       private Condition fullC;  //信号量

       private Condition emptyC;  //信号量

      

       private int size;

       public Queue(int size) {

          this.size = size;

          //(2)为信号量附初值

          fullC = lock.newCondition();

          emptyC = lock.newCondition();

       }

       LinkedList<Integer> list = newLinkedList<Integer>();

       /**

        * 入队

        *@return

        */

       public boolean EnQueue(int data) {

          lock.lock();//上锁

          while(list.size()>=size) {

             fullC.await();

          } catch (InterruptedException e) {

             lock.unlock();

             return false;

          }

       }

          list.addLast(data);

          emptyC.signalAll();

          lock.unlock();

          return true;

       }

       /**

        * 出队

        *@return

        */

       public int DeQueue() {

          lock.lock();//线上所

          while(list.size() == 0) {

             try {

                emptyC.await();

             }catch (InterruptedException e) {

                lock.unlock();

                return -1;//失败返回

             }

          }

          int r = list.removeFirst();//获取队列头部

          fullC.signalAll();//唤醒所有生产者

          lock.unlock();//解锁

          return r;

       }

            

       public boolean isFull() {

          return list.size()>=size;

       }

       public boolean isEmpty() {

          return list.size()==0;

       }

    }

     

    3.3.2 producer实验:

    package org.yang;

    import java.util.concurrent.locks.Condition;

    import java.util.concurrent.locks.Lock;

    /**

     * 生产者

     */

    publicclassProducer implementsRunnable {

       private Queue q;

       private Condition isFull; //信号量如果满了则等待

       private Condition isEmpty; //信号量如果空了则等待

       private Lock lock;

       privateintindex; //生产者的编号

       public Producer(intindex,Queue q,Lock lock,Condition isFull,Condition isEmpty) {

          this.index = index;

          this.q= q;

          this.isFull = isFull;

          this.isEmpty = isEmpty;

          this.lock = lock;

       }

       @Override

       publicvoid run() {

          lock.lock();

          if(q.isFull()) {

             try {

                isFull.await(); //如果队列为慢,则等待

             }catch(InterruptedException e) {

                return;

             }       

          }

          //生产并入队

          inta = (int) (Math.random()*1000);

          q.EnQueue(a);

          //生产完后

          isEmpty.signalAll();//把消费者唤醒。

          lock.unlock();

       }

    }

    3.4 测试

    3.4.1实验TestPC:

    package org.yang;

    publicclassTestPC {

       static Queue queue = new Queue(5);

       publicstaticvoid main(String[] args) {

          //创建三个生产者

          for(inti=0;i<3;i++) {

             finalintindex = i;

             new Thread(()->{

                intdate =(int)(Math.random()*1000);

                System.out.printf("thread %d want to EnQueue %d\n",index,date);

                queue.EnQueue(date);

                System.out.printf("thread %d EnQueue %d Success\n",index,date);

                sleep();//随机休息一段时间

             }

          }).start();

       }

       //创建消费者

       for(inti = 0;i<3;i++) {

          finalintindex = i;

          new Thread(()->{

             while(true) {

                System.out.printf("customer thread %d want to DnQueue %d\n",index);

                intdata = queue.DeQueue();

                System.out.printf("customer thread %d Finish DnQueue %dSuccess\n",index,date);

                sleep2();//随机休息一段时间

             }

          }).start();

       }

          }

       }

       //sleep随机时间

       publicstaticvoid sleep() {

          int t = (int)(Math.random()*100);

          try {

             Thread.sleep(t);

          }catch(InterruptedException e) {

             e.printStackTrace();

          }

       }

    3.4.2 当生产能力超出消费能力时的表现

    publicstaticvoidsleep() {

          int t = (int)(Math.random()*100);

          try {

             Thread.sleep1(t);

          }catch(InterruptedException e) {

             e.printStackTrace();

          }

       }

     

    3.4.3 当生产能力弱于消费能力时的表现

    System.out.printf("customer thread %d want to DnQueue %d\n",index);

                intdata = queue.DeQueue();

                System.out.printf("customer thread %d Finish DnQueue %dSuccess\n",index,date);

                sleep2();//随机休息一段时间

             }

          }).start();

       }

          }

    4 总结

          整个程序的设计过程中出现了很多问题,比如在设计过程中该设计几个类,各个类该完成什 么样的功能,如何实现各个功能,一个类如何调用另一类中的变量、如何处理事件等等许多问题,在代码设计过程中,对JAVA 面向的思想有了更深入的了解,程序中用到了很多操作系统的思想, 操作,信号量的互斥实现,线程的概念,对这些概念理解的更加透彻。

          实验过程的同时认识到了自己的不足,在以后的学习中应更加努力。在开始写代码前,一定要有个整体的规划,如设计几个类,每个类完成什么样的功能,应该设计几个变量,几个方法,各个方法能完成的功能等等。在写代码时,遵循 Java 编程规范。

    展开全文
  • 操作系统实践报告

    2012-07-03 18:21:16
    自考计算机本科专业操作系统实践报告二 1.实验题目 模拟采用二级目录结构的磁盘文件系统中的文件操作。 2.实验目的 (1)进一步认识文件系统的内部功能以及内部实现; (2)深入理解操作系统中文件系统的理论知识...
  • 操作系统实践报告

    2012-07-03 18:22:32
    自考计算机本科专业操作系统实践报告七 1.实验题目 编写程序模拟磁盘移臂调度。 2.实验目的 (1)进一步认识磁盘的驱动调度; (2)深入理解磁盘驱动调度中的移臂调度,并熟知各种移臂调度算法。 3.实验要求 (1...
  • 操作系统实践报告

    2012-07-03 18:19:00
    自考计算机本科专业操作系统课程实践一的报告
  • 华东师范大学高分操作系统实验报告,里面做的斯坦福大学pintos的两个主要实验,实验一认真完成有详细步骤和方案,实验2好多地方不懂,仅供参考
  • 先来先服务、短作业优先算法 多线程等的程序设计及实验心得体会
  • 自考本科,操作系统实践报告。包含了实践原理,实践内容,实践结果,实践分析以及实践心得。
  • 学习在Linux中产生一个系统调用以及怎样通过往Linux内核中增加一个新函数从而在该内核空间中实现对用户空间的读写。这个函数的功能是返回当前的系统时间。
  • Linux操作系统设计实践报告一,有关fork函数的相关验证等
  • PAGE4 / NUMPAGES10 Linux 操作系统概述 调研时间2011/12/2 1400到1630 摘要 随着网络应用越来越广泛,对各种嵌入式系统的网络功能要求越来越高.希望系统能够支持TCP/IP及其他Internet协议,使我们能够通过用户熟悉的...
  • 福州大学Linux 操作系统设计实践报告之文件操作,包括创建文件,读取键盘输入的内容存入文件,文件的读写
  • 它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。简单的来讲进程的概念主要有两点:第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括...

    课程总结

    1 线程的创建与启动

    1.1 进程与线程

    1、进程(process

    狭义定义:进程就是一段程序的执行过程。

    广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

    简单的来讲进程的概念主要有两点第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。第二,进程是一个执行中的程序。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。

    进程状态:进程有三个状态,就绪、运行和阻塞。就绪状态其实就是获取了出cpu外的所有资源,只要处理器分配资源就可以马上执行。就绪状态有排队序列什么的,排队原则不再赘述。运行态就是获得了处理器分配的资源,程序开始执行。阻塞态,当程序条件不够时候,需要等待条件满足时候才能执行,如等待i/o操作时候,此刻的状态就叫阻塞态。

    2、程序

    说起进程,就不得不说下程序。先看定义:程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程则是在处理机上的一次执行过程,它是一个动态的概念。这个不难理解,其实进程是包含程序的,进程的执行离不开程序,进程中的文本区域就是代码区,也就是程序。

    3、线程

    通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。

    4、多线程

    在一个程序中,这些独立运行的程序片段叫作线程Thread),利用它编程的概念就叫作多线程处理。多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。

    最简单的比喻多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理火车也不可能只有一节车厢。多线程的出现就是为了提高效率。

     

    进程与线程的区别:

    进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

    1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

    2) 线程的划分尺度小于进程,使得多线程程序的并发性高。

    3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

    4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

    5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

     

    优缺点 
    线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

    1.2 Java中的ThreadRunnable

    1.3 三种创建线程的办法

    第一种:

    package bao;

    /**

     * java.doc

     * @author Administrator

     *

     */

    class MyR implementsRunnable{

       private String msg;

     

       public MyR(String msg) {

         this.msg = msg;

        

       }

     

       @Override

       publicvoid run() {

         while(true) {

            try {

              Thread.sleep(1000);

              System.out.println(msg);

            }catch(InterruptedException e) {

              // TODO Auto-generated catch block

              e.printStackTrace();

              break;

            }

       }

       }

      

    }

    publicclassTestthread {

     

       publicstaticvoid main(String[] args) {

         Threadthread1= newThread(newMyR("hello"));

         thread1.start();

         Threadthread2= newThread(newMyR("hhhhh"));

         thread2.start();

        

       }

     

    }

    第二种:

    package bao;

     

    publicclassTesttheard2 {

     

       publicstaticvoid main(String[] args) {

         Testtheard2testtheard2= newTesttheard2();

            //匿名信匿名类

         Runnablerunnable= new Runnable() {

                @Override

              publicvoid run() {

                while(true) {

                 try {

                   Thread.sleep(1000);

                   System.out.println("haha");

                 }catch(InterruptedException e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

                   break;

                 }

                

                }

                }

            };

           

            Threadthread= newThread(runnable);

            Thread.start();

       }

     

    }

     

    第三种:

    package bao;

     

    import javax.xml.stream.events.StartDocument;

     

    publicclassTestthread3 {

     

       publicstaticvoid main(String[] args) {

          new Thread(newRunnable() {

           

            @Override

            publicvoid run() {

              while(true) {

                 try {

                   Thread.sleep(1000);

                   System.out.println("123");

                 }catch(InterruptedException e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

                   break;

                 }

             

            }

         }

     

       }).start();

          new Thread(()->{

          System.out.println("123");

             

          }).start();

       }

     

    }

     

    2 线程简单同步(同步块)

    2.1 同步的概念和必要性

    同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。

    字从字面上容易理解为一起动作

    其实不是,字应是指协同、协助、互相配合。

    如进程、线程同步,可理解为进程或线程AB一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给AA再继续操作。

    所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其它线程也不能调用这个方法。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。例如Window API函数SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的LRESULT值返回给调用者。

    在多线程编程里面,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。

    为什么要同步?

    因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常。举个例子,如果一个银行账户同时被两个线程操作,一个取100块,一个存钱100块。假设账户原本有0块,如果取钱线程和存钱线程同时发生,会出现什么结果呢?取钱不成功,账户余额是100.取钱成功了,账户余额是0.那到底是哪个呢?很难说清楚。因此多线程同步就是要解决这个问题。

    2.2 synchronize关键字和同步块

    Synchronize 关键字是解决并发问题常用解决方案,有以下三种使用方式:

    ·        同步普通方法,锁的是当前对象。

    ·        同步静态方法,锁的是当前 Class 对象。

    ·        同步块,锁的是 {} 中的对象。

     

    同步块:

    1.从包含的代码量来说,同步代码块比同步方法小。我们可以把同步代码块比喻成是没上锁房间里的多了一层带锁的内门。

    2.带锁的内门可以由用户自定义其钥匙,你可以用本房的钥匙,你也可以指定用一个房子的钥匙才能开,这样的话,你要跑到另一栋房子那儿把那个钥匙拿来,并用那个房子的钥匙来打开这个房子的带锁的内门。

    3.记住你获得的那另一栋房子的钥匙,并不影响其他人进入那栋房子没有锁的房间。

     

    2.3 实例

    package bao;

    import java.util.ArrayList;

    import javax.swing.text.StyledEditorKit.ForegroundAction;

     

    import com.sun.media.jfxmedia.events.NewFrameEvent;

     

    publicclasstest5 {

     staticintc=0;

    privatestaticObject lock=newObject();//创建一个锁变量

       publicstaticvoid main(String[] args) {

         Thread[]threads= newThread[1000];

       for(inti=0;i<1000;i++) {

         finalintindex =i;

         threads[i]= new Thread(()->{

            synchronized(lock) {//创建一个同步块,需要一个锁

              System.out.println("thread "+index+" enter");//输出

         inta = c;

         a++;

          try {

            Thread.sleep((long) (Math.random()*1000));

         }catch(Exception e) {

            e.printStackTrace();

         }

         c=a;//存回去

         System.out.println("thread "+index+" leave");

            }

       });

       threads[i].start();

     }

       for(inti=0;i<1000;i++) {

         try {

            threads[i].join();

         }catch(InterruptedException e) {

            e.printStackTrace();

         }

       }

       System.out.print("c="+c);

     

    }

    }

     

    3 生产者消费者问题

    3.1 问题表述

    生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区线程——即所谓的生产者消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

    3.2 实现思路

    要解决该问题,就必须让生产者在缓冲区满时休眠,等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。

    3.3 Java实现该问题的代码

    生产者消费者
    队列Queue

    package org.yang;

     

    import java.util.LinkedList;

    import java.util.concurrent.locks.Condition;

    import java.util.concurrent.locks.Lock;

    import java.util.concurrent.locks.ReentrantLock;

     

    publicclassQueue { //队列

       private Lock lock = new ReentrantLock();

       private Condition fullC; //信号量

       private Condition emptyC; //信号量 

       privateintsize;

       public Queue(intsize) {

         this.size  = size;

         fullC = lock.newCondition();

         emptyC = lock.newCondition();

       }

       LinkedList<Integer>list= newLinkedList<Integer>();

       /**

        * 入队

        * @return

        */

       publicboolean EnQueue(intdata) {

         lock.lock();

         while(list.size()>=size) {

            try {

              fullC.await();

            }catch(InterruptedException e) {

              lock.unlock();

              returnfalse;

            }

         }

         list.addLast(data);

         emptyC.signalAll();

         lock.unlock();

         returntrue;

       }

       /**

        * 出队

        * @return

        */

       publicint DeQueue() {

         lock.lock();

         if(list.size() == 0) {

            try {

              emptyC.await();

            }catch(InterruptedException e) {

              lock.unlock();

               return -1;

            }

         }

         intr = list.removeFirst();

         fullC.signalAll();

         lock.unlock();

         returnr;

       }

       publicboolean isFull() {

         returnlist.size()>=size;

       }

       publicboolean isEmpty() {

         returnlist.size()==0;

       }

    }

    生产者消费者

    package org.yang;

     

    import java.util.concurrent.ThreadLocalRandom;

     

    publicclassTestA {

       staticQueue queue= newQueue(5);

       publicstaticvoid main(String[] args) {

         for(inti=0;i<3;i++) {

            finalintindex = i;

            new Thread(()->{

              intdata =(int)(Math.random()*1000);

               System.out.printf("produce thread %d want to EnQueue %d\n",index,data);

              queue.EnQueue(data);

              System.out.printf("produce thread %d EnQueue %d Success\n",index,data);

              sleep();

            }).start();

         }

         for(inti=0;i<3;i++) {

            finalintindex=i;

            new Thread(()->{

              System.out.printf("customer thread %d want to EnQueue\n",index);

              intdata = queue.DeQueue();

              System.out.printf("customer thread %d EnQueue %d Success\n",index,data);

            }).start();

         }

       }

       publicstaticvoid sleep() {

         intt =(int)(Math.random()*100);

         try {

            Thread.sleep(t);

         }catch(Exception e) {

            // TODO: handle exception

            e.printStackTrace();

         }

       }

       }

     

    3.4 测试

    3.4.1 当生产能力超出消费能力时的表现

    produce thread 0 want to EnQueue 931

    produce thread 0 EnQueue 931 Success

    customer thread 1 want to EnQueue

    customer thread 1 EnQueue 931Success

    produce thread 2 want to EnQueue 185

    produce thread 2 EnQueue 185 Success

    customer thread 2 want to EnQueue

    customer thread 2 EnQueue 185Success

    customer thread 0 want to EnQueue

    produce thread 1 want to EnQueue 878

    produce thread 1 EnQueue 878 Success

    customer thread 0 EnQueue 878Success

     

    3.4.2 当生产能力弱于消费能力时的表现

    produce thread 0 want to EnQueue 4

    produce thread 0 EnQueue 4 Success

    customer thread 1 want to EnQueue

    customer thread 1 EnQueue 4 Success

    produce thread 2 want to EnQueue 7

    produce thread 2 EnQueue 7 Success

    customer thread 2 want to EnQueue

    customer thread 2 EnQueue 7 Success

    customer thread 0 want to EnQueue

    produce thread 1 want to EnQueue 9

    produce thread 1 EnQueue 9 Success

    customer thread 0 EnQueue 9 Success

    4.总结

    从理论到实践,确实学到了很多东西,在调试过程中遇到了很多的麻烦,但通过老师的讲解和同学们的帮助成功解决了这些问题,使我明白了编写程序一点都不能马虎,通过这次实践,我更加深刻的了解到了线程和进程的区别,经过了编程,懂得了创建线程的方法,了解了简单的线程同步,更加深入的了解了生产者消费者的问题。


    展开全文
  • Linux操作系统设计实践报告二.有几个小实验,包括客户端与服务器端消息互通的简单机制
  • 操作系统编程实践课程设计报告,主要讲Java多线程实现进程和线程的同步问题。
  • 福州大学Linux 操作系统设计实践报告之图形界面gtk
  • 福州大学Linux 操作系统设计实践报告之进程管理,父进程与子进程间的关系
  • 福州大学Linux 操作系统设计实践报告之进程通信,进程间通信之命名管道,进程间的通信之消息队列
  • 福州大学Linux 操作系统设计实践报告之综合应用,一个基于gtk编程的学籍管理系统,可实现学籍的添加,删除和修改等简单的功能
  • 陕西省 西安电子科技大学 计算机应用实践报告 操作系统 doc
  • 操作系统实践

    2018-07-04 17:49:18
    操作系统实践总结报告1 线程的创建与启动1.1 进程与线程主要描述进程线程概念和差别。进程概念:一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位线程概念:一个...

    操作系统实践总结报告

    1 线程的创建与启动

    1.1 进程与线程

    主要描述进程线程概念和差别。

    进程概念:一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位

    线程概念:一个进程内部可能包含了很多顺序执行流,每个顺序执行流就是一个线程。

    线程与进程的区别:

    1.一个程序至少有一个进程,一个进程至少有一个线程

    2.线程的划分尺度小于进程,使得多线程程序的并发性高

    3.进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率

    4.每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制

    5.多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配

     

    1.2 Java中的Thread和Runnable类

    实现Runnable接口比继承Thread类所具有的优势:

    1):适合多个相同的程序代码的线程去处理同一个资源

    2):可以避免java中的单继承的限制

    3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

     

    1.3 三种创建线程的办法

    1)继承Thread类创建线程:

    通过继承Thread类来创建并启动多线程的一般步骤如下

    1.d定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。

    2.创建Thread子类的实例,也就是创建了线程对象

    3.启动线程,即调用线程的start()方法

     

    2)实现Runnable接口创建线程:

    通过实现Runnable接口创建并启动线程一般步骤如下:

    1.定义Runnable接口的实现类,一样要重写run()方法,这个run()方法和Thread中的run()方法一样是线程的执行体

    2.创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象

    3.第三部依然是通过调用线程对象的start()方法来启动线程

     

    3)使用Callable和Future创建线程:

    1.创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例(从java8开始可以直接使用Lambda表达式创建Callable对象)。

    2.使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值

    3.使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口)

    4.调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

     

     

    Runnable接口创建线程

    package ly;

    /**

     * Runnable的实现类,是线程执行的主体。

     * run函数是入口

     * @author Administrator

     *

     */

    class MyR implementsRunnable{

       private String msg;

     

       public MyR(String msg) {

         this.msg=msg;

       }

     

       @Override

       publicvoid run() {

         while(true) {

            try {

               Thread.sleep(1000);

              System.out.println(msg);

            }catch(InterruptedException e) {

              e.printStackTrace();

              break;

            }

         }

       }

      

    }

     

    publicclassTestThread {

       publicstaticvoid main(String[] args) {

         Threadthread1=newThread(newMyR("hello"));

         thread1.start();

         Threadthread2=newThread(newMyR("wuwu"));

         thread2.start();

        

      

       }

     

    }

     

     

     

     

    Thread类创建线程:

     

    package ly;

     

    publicclassTestThread2 {

     

       publicstaticvoid main(String[] args) {

         TestThreadtestThread2=new TestThread();

         Runnablerunnable=new Runnable() {

            publicvoid run() {

              while(true) {

                 try {

                   Thread.sleep(1000);

                   System.out.println("haha");

                 }catch(InterruptedException e) {

                   e.printStackTrace();

                   break;

              }

             

            }

            }

         };

         Threadthread=newThread(runnable);

         thread.start();

         }

    }

     

     

        

      

     

    CallableFuture创建线程:

    package ly;

     

    publicclassTextThread3 {

     

       publicstaticvoid main(String[] args) {

         new Thread(new Runnable(){

            publicvoid run() {

             

           

             

                

                 System.out.println("haha");

             

            }

             

           

            }).start();

           

        

      

         new Thread(()-> {

            System.out.println("haha");

         }).start();

       }

     

    }

    线程简单同步(同步块)

    2.1 同步的概念和必要性

     为什么要同步,可以举例说明

    概念:同步是一个操作系统级别的概念,是在多道程序的环境下,存在着不同的制约关系,为了协调这种互相制约的关系,实现资源共享和进程协作,从而避免进程之间的冲突,引入了同步。

    必要性:如果不能采取有效的措施,对多个进程的运行进行妥善的管理,必然会因为这些进程对系统资源的无序争夺给系统造成混乱,此时就需要同步机制。

     

    2.2 synchronize关键字和同步块

    同步块

    Java 同步块用来标记方法或者代码块是同步的。Java 同步块用来避免竞争。Java 中的同步块用 synchronized 标记。

    synchronize关键字机制

    synchronize修饰方法

    1、使用synchronize关键字的方法性能比较低

    2、每一个使用synchronize修饰的方法都是临界区

    3、使用synchronize修饰的对象,那么同一时间只能有一个执行线程访问,如果其他线程试图访问这个对象的其他方法,都将被挂起

     

    2.3 实例

    线程的同步:

    package ly;

     

    import com.sun.media.jfxmedia.events.NewFrameEvent;

     

    publicclasstestSync {

     

        staticintc;

        static Object lock=new Object();

       publicstaticvoid main(String[] args) {

         Thread[]threads=newThread[1000];

         for(inti=0;i<1000;i++) {

            finalintindex =i;

            threads[i]=new Thread(() ->{

              synchronized(lock) {

                 System.out.println("thread"+index+"enter");

              inta= c;

              a++;

              try {

                 Thread.sleep((long)(Math.random()*1000));

              }catch(InterruptedException e) {

                 e.printStackTrace();

              }

              c=a;

              }

            });

            threads[i].start();

         }

         for(inti=0;i<1000;i++) {

            try {

              threads[i].join();

            }catch(InterruptedException e) {

              e.printStackTrace();

         }

         // TODO Auto-generated method stub

     

       }

         System.out.print("c="+c);

     

    }

    }

    3 生产者消费者问题

    3.1 问题表述

    生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区线程——即所谓的生产者消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

     

    3.2 实现思路

    用自然语言描述这个问题的解决思路

    有一群生产者进程在生产产品,并将这些产品提供给消费者进程去消费。为使生产者进程与消费者进程能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者进程将其所生产的产品放入一个缓冲区中;消费者进程可从一个缓冲区中取走产品取消费。

    3.3 Java实现该问题的代码

    package ly;

     

    import java.util.LinkedList;

    import java.util.concurrent.locks.Condition;

    import java.util.concurrent.locks.Lock;

    import java.util.concurrent.locks.ReentrantLock;

     

    publicclassQueue {

       private Lock lock=new ReentrantLock();

       private Condition fullC;

       private Condition emptyC;

       privateintsize;

       public Queue(intsize) {

         this.size=size;

         fullC= lock.newCondition();

         emptyC= lock.newCondition();

       }

       LinkedList<Integer>list=newLinkedList<Integer>();

       /**

        * 入队

        */

       publicboolean EnQueue(intdata) {

         lock.lock();

         while(list.size()>=size) {

            try {

              fullC.await();

            }catch(InterruptedException e) {

              returnfalse;

            }

        

         }

         list.addLast(data);

         emptyC.signalAll();

         lock.unlock();

         returntrue;

       }

      

       /**

        * 出队

        * @param args

        */

       publicint DeQueue() {

         lock.lock();

         while(list.size()==0) {

            try {

              emptyC.await();

            }catch(InterruptedException e) {

              lock.unlock();

              return -1;

            }

         }

         intr=list.removeFirst();

         fullC.signalAll();

         lock.unlock();

         returnr;

       }

       publicboolean isFull() {

         returnlist.size()==0;

       }

       publicboolean isEmpty() {

         returnlist.size()==0;

       }

     

    }

    package ly;

     

    import javax.net.ssl.SSLException;

     

    publicclassTestPC {

       static Queue queue=new Queue(5);

     

       publicstaticvoid main(String[] args) {

         for(inti=0;i<3;i++) {

            finalintindex=i;

            new Thread(()-> {

              intdata=(int)(Math.random()*1000);

              System.out.printf("thread %d want to EnQueue %d\n"+data);

              queue.EnQueue(data);

              System.out.printf("thread %d EnQueue %d Success\n"+data);

              sleep();

            }).start();

         }

         for(inti=0;i<3;i++) {

              finalintindex=i;

              new Thread(()-> {

                 while(true) {

                 System.out.printf("customer thread %d want to DnQueue %d\n",index);

                 intdata =queue.DeQueue();

                 System.out.printf("customer thread %d DnQueue %d Success\n",index,data);

                 sleep();

                 }

              }).start();

            }

           

         }

        

      

       publicstaticvoid sleep() {

         intt=(int)(Math.random()*1000);

         try {

            Thread.sleep(t);

         }catch(InterruptedException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

         }

       }

    }

     

    3.4 测试

    3.4.1 当生产能力超出消费能力时的表现

    produce thread 0 want toEnQueue 189

    produce thread 0 EnQueue 189Success

    customer thread 1 want toEnQueue

    customer thread 1 EnQueue 189Success

    produce thread 2 want toEnQueue 148

    produce thread 2 EnQueue 148Success

    customer thread 2 want toEnQueue

    customer thread 2 EnQueue 148Success

    customer thread 0 want toEnQueue

    produce thread 1 want toEnQueue 21

    produce thread 1 EnQueue 21Success

    customer thread 0 EnQueue 21Success

    3.4.2 当生产能力弱于消费能力时的表现

    produce thread 0 want toEnQueue 7

    produce thread 0 EnQueue 7Success

    customer thread 1 want toEnQueue

    customer thread 1 EnQueue 7Success

    produce thread 2 want toEnQueue 6

    produce thread 2 EnQueue 6Success

    customer thread 2 want toEnQueue

    customer thread 2 EnQueue 6Success

    customer thread 0 want toEnQueue

    produce thread 1 want toEnQueue 7

    produce thread 1 EnQueue 7Success

    customer thread 0 EnQueue 7Success

    4 总结

    通过操作系统的实践,让我更加清楚了操作系统的运行,这次实践课我们对线程的创建做了一次实验,了解到了线程创建的三种方式和线程的同步,对生产者-消费者问题做了一次关键性的实验,是我对这个经典问题的理解不再停留在书面所写的知识上。这次实践课使我对操作系统这门课程的理解更加明白,使我动手与思考的能力加强了不少。

     

     

    展开全文
  • 实验2 系统调用 实验3 内核模块 实验4 设备驱动 实验说明: 1. 实验做为学习的重要促进手段,是为了深化对理论的理解,锻炼实践动手能力。 2. 实验同时也作为考核的手段。 3. 实验内容会在课程进行中下达,...
  • 操作系统编程实践

    2018-07-04 18:21:48
    操作系统编程实践报告1 线程的创建与启动1.1 进程与线程线程与进程的比较:1. 调度的基本单位:线程是程序执行的最小单位,进程是资源分配的最小单位2. 并发性:进程之间;同一进程的多线程之间3. 拥有资源:进程...

          操作系统编程实践报告

    1 线程的创建与启动

    1.1 进程与线程

    线程与进程的比较:

    1.     调度的基本单位:线程是程序执行的最小单位,进程是资源分配的最小单位

    2.     并发性:进程之间;同一进程的多线程之间

    3.     拥有资源:进程可以拥有资源,线程不拥有资源

    4.     系统开销:线程只保存少量寄存器,不涉及存储器管理

    1.2 Java中的Thread和Runnable类

    Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,创建名为MyR的类,作为Runnable接口的实现类并复写run()方法,用while循环控制输出,就可以启动新线程并执行自己定义的run()方法

    1.3 三种创建线程的办法

    1、继承Thread类创建线程

    packagesrc;

    classMyR implementsRunnable{

    private String msg;

    public MyR(String msg){

    this.msg=msg;

    }

        @Override

        publicvoidrun() {

           while(true){

               try {

                  Thread.sleep(1000);

               }catch (InterruptedException e) {

                  e.printStackTrace();

                  break;

               }

           }

          

        }

       

    }

    publicclass teseheard {

     

        publicstaticvoid main(String[] args) {

           Threadthread1 = new Thread(new MyR("hello"));

           thread1.start();

           Threadthread2 = new Thread(new MyR("wuwu"));

           thread2.start();

        }

    }

    2、实现Runnable接口创建线程
    package org.yang;

     

    public classTestThread2 {

     

        public static void main(String[] args) {

          //创建匿名类,引用就是指针

           Runnable runnable = new Runnable() {//Runnable是一个接口

     

               @Override

               public void run() {

                   while(true){

                          try {

                             System.out.println("haha");

                             Thread.sleep(1000);

                         } catch (InterruptedException e) {

                             e.printStackTrace();

                             break;

                         }

                       }    

                  }

           };

           Thread thread = new Thread(runnable);

           thread.start();

        }

     

    }

    3.第三个实验中,用两种方法创建线程

    package org.yang;

     

    import javax.swing.event.TreeWillExpandListener;

     

    public class TestTread3{

     

        public static void main(String[] args) {

           new Thread(new Runnable() {

              

               @Override

               public void run() {

                   System.out.println("haha");

                  }

           }).start();

          

           //lambda 表达式 java 1.8+

           new Thread(()->{

               System.out.println("haha");

           }).start();

        }

     

    }

    2 线程简单同步(同步块)

    2.1 同步的概念和必要性

    线程同步的概念:当使用多个线程来访问同一个数据时,非常容易出现线程安全问题(比如多个线程都在操作同一数据导致数据不一致),所以我们用同步机制来解决这些问题。

    为了加深理解,下面举几个例子。 
    有两个采购员,他们的工作内容是相同的,都是遵循如下的步骤: 
    (1)到市场上去,寻找并购买有潜力的样品。 
    (2)回到公司,写报告。 
    这两个人的工作内容虽然一样,他们都需要购买样品,他们可能买到同样种类的样品,但是他们绝对不会购买到同一件样品,他们之间没有任何共享资源。所以,他们可以各自进行自己的工作,互不干扰。 
    这两个采购员就相当于两个线程;两个采购员遵循相同的工作步骤,相当于这两个线程执行同一段代码。

    下面增加一个角色。一个办公室行政人员这个时候,也走到了布告栏前面,准备修改布告栏上的信息。 
    如果行政人员先到达布告栏,并且正在修改布告栏的内容。两个采购员这个时候,恰好也到了。这两个采购员就必须等待行政人员完成修改之后,才能观看修改后的信息。如果行政人员到达的时候,两个采购员已经在观看布告栏了。那么行政人员需要等待两个采购员把当前信息记录下来之后,才能够写上新的信息。 
    上述这两种情况,行政人员和采购员对布告栏的访问就需要进行同步。因为其中一个线程(行政人员)修改了共享资源(布告栏)。而且我们可以看到,行政人员的工作流程和采购员的工作流程(执行代码)完全不同,但是由于他们访问了同一份可变共享资源(布告栏),所以他们之间需要同步

    2.2 synchronize关键字和同步块

     synchronized关键字

    synchronized用于解决线程同步问题,当有多条线程同时访问共享数据时,如果不进行同步,就很可能会发生错误,java提供的解决方案是:只要将操作共享数据的代码在某一时间让一个线程执行完,在执行过程中,其他线程不能执行同步代码,这样就可以保护数据的正确性。

    Synchronize 关键字是解决并发问题常用解决方案,有以下三种使用方式:

    ·        同步普通方法,锁的是当前对象。

    ·        同步静态方法,锁的是当前 Class 对象。

    ·        同步块,锁的是 {} 中的对象

    synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
    (1)修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
    (2)修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
    (3)修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
    (4)修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

    同步方法与同步代码块

    同步方法

    1.同步方法 

     即有synchronized关键字修饰的方法。 

     由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

        代码如: 

        public synchronized voidsave(){}

     

       注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类

    2.同步代码块 

     即有synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步

        代码如: 

        synchronized(object){ 

        }


    synchronized
    方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
    public synchronized void drawMoney()

    synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。

    synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是 synchronized 块。

    2.3 实例

    package org.yang;

     

    public class TestSync {

        static int c = 0;

        public static void main(String[] args) {

           Thread[] threads = new Thread[1000];

           for(int i=0;i<1000;i++) {

               threads[i] = new Thread(()->{

                  int a = c;//获取c的值

                  a++;//将值加一

                  try {//模拟复杂处理过程

                      Thread.sleep((long)(Math.random()*1000));

                  } catch(InterruptedException e) {

                      e.printStackTrace();

                  }

                  c=a;//存回去

               });

               threads[i].start();//线程开始

           }

           for(int i=0;i<1000;i++) {

               try {

                  threads[i].join();//等待thread i的完成

               }catch(InterruptedException e) {

                  e.printStackTrace();

               }

           }//循环后,所有的线程都完成了

           System.out.print("c="+c);//输出c的结果

        }

     

    }

     

    一个进程进,等它出来后,下一个进程才能进去,最后c的值为1000。

    1、随便建立一个变量,作为锁变量

    2、创建一个同步块,需要一个锁

    3、建立了一个final变量,方便在lamdba中使用

    4、输出

    改进代码:

    package org.yang;

     

    import com.sun.media.jfxmedia.events.NewFrameEvent;

     

    public class TestSync {

        static int c = 0;

        static Object lock = new Object();//1、随便建立一个变量,作为锁变量

        public static void main(String[] args) {

           Thread[] threads = new Thread[1000];

           for(int i=0;i<1000;i++) {

               final int index = i;//4、建立了一个final变量,方便在lambda中使用

               threads[i] = new Thread(()->{

                  synchronized (lock) {//2、创建了一个同步块,需要一个锁

                      System.out.println("thread"+index+"enter");//5、输出

                 

                  int a = c;//获取c的值

                  a++;//将值加一

                  try {//模拟复杂处理过程

                      Thread.sleep((long)(Math.random()*10));

                  } catch(InterruptedException e) {

                      e.printStackTrace();

                  }

                  c=a;//存回去

                  System.out.println("thread"+index+"leave");//6、输出

                  }//3、这是块的终结

               });

               threads[i].start();//线程开始

           }

           for(int i=0;i<1000;i++) {

               try {

                  threads[i].join();//等待thread i的完成

               }catch(InterruptedException e) {

                  e.printStackTrace();

               }

           }//循环后,所有的线程都完成了

           System.out.print("c="+c);//输出c的结果

        }

     

    }

    3 生产者消费者问题

    3.1 问题表述

    生产者-消费者(Producer-Consumer)问题是著名的进程同步问题。它描述一组生产者向一组消费者提供消息,它们共享一个有界缓冲池,生产者向其中投放消息,消费者从中取得消息。以下用信号量解决生产者-消费者问题。

    3.2 实现思路

    定义四个信号量:

    empty——表示缓冲区是否为空,初值为n

    full——表示缓冲区中是否为满,初值为0

    mutex1——生产者之间的互斥信号量,初值为1

    mutex2——消费者之间的互斥信号量,初值为1

    设缓冲区的编号为1n-1,定义两个指针inout,分别是生产者进程和消费者进程使用的指针,指向下一个可用的缓冲区。

     

    生产者进程

    while(TRUE){

         生产一个产品;

         P(empty);

         P(mutex1)

         产品送往bufferin);

         in=(in+1)mod n

         V(mutex1);

         V(full);

         }

    消费者进程

    while(TRUE){

     P(full);

       P(mutex2)

       bufferout)中取出产品;

       out=(out+1)mod n

       Vmutex2);

       V(empty);

    例子:在公共电话厅打电话

    公共电话厅里有多个电话,如某人要打电话,首先要进行申请,看是否有电话空闲,若有,则可以使用电话,如果电话亭里所有电话都有人正在使用,那后来的人只有排队等候。当某人用完电话后,则有空电话腾出,正在排队的第一个人就可以使用电话。这就相当于PV操作:

    某人要打电话,首先要进行申请,相当于执行一次P操作,申请一个可用资源(电话);

    某人用完电话,则有空电话腾出,相当于执行一次V操作,释放一个可用资源(电话)。

    3.3 Java实现该问题的代码

    package org.yang;

     

    import javax.print.attribute.standard.PrinterMessageFromOperator;

     

    public class TestPC {

        static Queue queue = new Queue(5);

        public static void main(String[] args) {

           //创建生产者

           for(int i=0;i<3;i++) {

               final int index =i;

               new Thread(()->{

                  while(true) {

                  int data = (int)(Math.random()*1000);

                  System.out.printf("Producer thread%d want to enque %d\n",index,data);

                  queue.EnQueue(data);

                  System.out.printf("Producer thread%d EnQueue %d Success\n",index,data);

                  sleep();//随机休息一段时间

                  }

               }).start();

           }

           //创建消费者

           for(int i=0;i<3;i++) {

               final int index =i;

               new Thread(()->{

                  while(true) {

                  System.out.printf("Consumer thread%d want to Dequeue\n",index);

                  int data = queue.DeQueue();

                  System.out.printf("Consumer thread%d DeQueue %d Success\n",index,data);

                  sleep2();//随机休息一段时间

                  }

                 

               }).start();

           }

        }//sleep随机时间

        public static void sleep() {

           int t =(int)(Math.random()*100);

           try {

               Thread.sleep(t);

               } catch(InterruptedException e) {

                  e.printStackTrace();

               }

        }

        public static void sleep2() {

           int t =(int)(Math.random()*100);

           try {

               Thread.sleep(t);

               } catch(InterruptedException e) {

                  e.printStackTrace();

               }

        }

    }

    3.4 测试

    3.4.1 当生产能力超出消费能力时的表现

        当生产能力超出消费能力时,生产者进程等待,可以调大生产者的sleep(),调小消费者的sleep(),从而加快消费者进程,将生产者进程唤醒。

    3.4.2 当生产能力弱于消费能力时的表现

    当生产能力弱于消费能力时,消费者进程等待,可以调小生产者的sleep(),调大消费者的sleep(),从而加快生产者进程,将消费者进程唤醒。

    4 总结

    通过本次实验,我对进程的调度有了更深层次的了解掌握,明白了进程的创建、控制、通信机制,掌握了线程和进程的区别,对生产者消费者问题有了更深层次的理解,学会了用synchronized解决线程同步问题,收获颇丰。虽然在实验过程中,我遇到很多困难,但是通过解决这些困难,我学到了很多。

     

    展开全文
  • 操作系统实验报告lab1

    2019-07-11 11:43:47
    只是我上大学自己当时写的lab1,感觉这个就是第一个是自己写的,国外的课程还是实践性还是很强的
  • 操作系统实验报告lab2

    2019-07-11 11:46:10
    只是我上大学自己当时写的lab2,感觉这个就是第一个是自己写的,国外的课程还是实践性还是很强的
  • 教育资料 教育资料 操作系统实验报告 实验序号 7 实验项目名称 Linux 存储管理操作实践 学号 姓名 专业班 实验地点 指导教师 实验时间 一实验目的及要求 通过本实验的学习使学生掌握 Linux 存储管理相关操作的基本...
  • 操作系统实验报告 实验序号 7 实验项目名称 Linux 存储管理操作实践 学 号 姓 名 专业班 实验地点 指导教师 实验时间 一实验目的及要求 通过本实验的学习使学生掌握 Linux 存储管理相关操作的基本方法 以学生自主...
  • 教育资料 操作系统实验报告 实验序号7 实验项目名称Linux存储管理操作实践 学 号 姓 名 专业班 实验地点 指导教师 实验时间 一实验目的及要求 通过本实验的学习使学生掌握Linux存储管理相关操作的基本方法 以学生...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 430
精华内容 172
关键字:

操作系统实践报告