精华内容
下载资源
问答
  • 进程同步和互斥

    2021-09-07 11:04:47
    一、进程同步和互斥概念 二、进程互斥的软件实现方法 三、进程互斥的硬件实现方法 四、信号量机制 可以解决进程同步、互斥问题 用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而实现进程...

    进程同步和互斥

    一、进程同步和互斥概念

    在这里插入图片描述

    二、进程互斥的软件实现方法

    在这里插入图片描述

    三、进程互斥的硬件实现方法

    在这里插入图片描述

    四、信号量机制

    可以解决进程同步、互斥问题

    用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而实现进程互斥(进程对临界资源的单独访问),进程同步(进程对临界资源的访问顺序)问题

    信号量听名字,好像是个跟信号、电气沾边的东西,其实信号量就是一个变量,用来表示系统资源数量,比如打印机的数量,也可以理解为操作系统层面的变量,每个进程共享

    注意信号量可以是整型变量,也可以是个结构体变量

    原语就是一种特殊的程序段,它的执行是一气呵成,不可被中断的,比如A用户先检查厕所没人,然后进去上锁,这两个步骤是连贯的;试想如果A用户先检查厕所没人,这个时候操作系统剥夺它的处理机资源,就绪队列B用户上处理机,也检查到厕所没人然后上厕所,后面再切换回A用户,A也上厕所,就会出现2个用户同时上1个厕所的尴尬局面(没有实现进程互斥)

    整型信号量

    用1个整数型变量作为信号量,数值表示某种资源

    跟普通整型变量区别,就是信号量只能执行初始化,申请、释放3种操作

    存在问题,还是没有满足让权等待原则

    记录型信号量

    //记录型信号量的定义
    typedef struct{
    	int value;//剩余资源数量
    	Struct process *L;//等待进程链表
    }semaphore;
    
    //使用时申请资源,资源不够进入等待队列
    void wait (semaphore S){
    	S.value--;//系统资源数减1
    	//如果当前没有系统资源,该进程进入等待队列
    	if(S.value <= 0){
    		block(S.L);
    	}
    }
    //使用完释放资源,顺便唤醒等待队列的第一个进程
    void signal(semaphore S){
    	S.value++;//系统资源数加1
    		//如果还有进程在等待队列,唤醒
    	if(S.value <= 0){
    		wakeup(S.L);
    	}
    }
    
    

    记录型信号量可以用来实现进程同步、进程互斥

    五、管程

    在这里插入图片描述

    展开全文
  • 六、进程同步和互斥 1、进程同步和互斥原则 2、进程互斥的软件实现方法 3、进程互斥的硬件实现方法

    五、进程同步和互斥

    1、进程同步和互斥原则

    1.1 进程同步的基本概念:进程同步的主要任务,是对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能够按照一定的规则(或时序)共享系统资源,并能很好的相互合作,从而使程序的执行具有可再现性。

    在这里插入图片描述

    2、进程互斥的软件实现方法

    在这里插入图片描述

    3、进程互斥的硬件实现方法

    在这里插入图片描述

    展开全文
  • 浅谈进程同步和互斥概念

    千次阅读 2018-04-14 15:17:43
    简介 进程同步是一个操作系统级别的概念,是在多道程序的环境下,存在着不同的制约关系,为了协调这种互相制约的关系,实现资源共享进程协作,从而避免进程之间的冲突,引入了进程同步。 临界资源 在操作系统中...

    简介

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

     

    临界资源

        在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源)。但对于某些资源来说,其在同一时间只能被一个进程所占用。这些一次只能被一个进程所占用的资源就是所谓的临界资源。典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。

        对于临界资源的访问,必须是互诉进行。也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。而进程内访问临界资源的代码被成为临界区

        对于临界区的访问过程分为四个部分:

        1.进入区:查看临界区是否可访问,如果可以访问,则转到步骤二,否则进程会被阻塞

        2.临界区:在临界区做操作

        3.退出区:清除临界区被占用的标志

        4.剩余区:进程与临界区不相关部分的代码

     

    进程间同步和互诉的概念

     

    进程同步

        进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。

        比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。而当进程A产生信息放入缓冲区时,进程B才会被唤醒。概念如图1所示。

        1

         图1.进程之间的同步

     

         用C#代码模拟进程之间的同步如代码1所示。

     class ProcessSyn
        {
            private static Mutex mut = new Mutex();
            
            
            static void Main()
            {
                Console.WriteLine("进程1执行完了进程2才能执行.......");
                Thread Thread1 = new Thread(new ThreadStart(Proc1));
                Thread Thread2 = new Thread(new ThreadStart(Proc2));
                Thread1.Start();
                Thread2.Start();
                Console.ReadKey();   
            }
           
            private static void Proc1()
            {
                mut.WaitOne();
                Console.WriteLine("线程1执行操作....");
                Thread.Sleep(3000);
                mut.ReleaseMutex();//V操作
    
            }
            private static void Proc2()
            {
                
    
                mut.WaitOne();//P操作
                Console.WriteLine("线程2执行操作....");
                mut.WaitOne();
            }
        }

        代码1.C#模拟进程之间的同步

     

        运行结果如图2所示。

        2

        图2.运行结果

     

    进程互斥

        进程互斥是进程之间的间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。

        比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。概念如图3所示。

        3

         图3.进程之间的互斥

     

         用C#模拟进程之间的互斥,这里我启动了5个线程,但同一时间内只有一个线程能对临界资源进行访问。如代码2所示。

    class ProcessMutex
        {
            private static Mutex mut = new Mutex();
            private const int numThreads = 5;
            
            static void Main()
            {
                
                for (int i = 0; i <= numThreads; i++)
                {
                    Thread myThread = new Thread(new ThreadStart(UseResource));
                    myThread.Name = String.Format("线程{0}", i + 1);
                    myThread.Start();
                }
                Console.ReadKey();
                
            }
            
            
            //同步
            private static void UseResource()
            {
                // 相当于P操作
                mut.WaitOne();
    
                
                /*下面代码是线程真正的工作*/
                Console.WriteLine("{0}已经进入临界区",
                    Thread.CurrentThread.Name);
                Random r = new Random();
                int rNum = r.Next(2000);
                
                Console.WriteLine("{0}执行操作,执行时间为{1}ms", Thread.CurrentThread.Name,rNum);
                Thread.Sleep(rNum);
    
                Console.WriteLine("{0}已经离开临界区\r\n",
                    Thread.CurrentThread.Name);
                /*线程工作结束*/
    
    
                
                // 相当于V操作
                mut.ReleaseMutex();
            }
            //互斥
      
    
    
        }

        代码2.C#模拟进程之间的互斥

     

         运行结果如图4所示。

        4   

        图4.C#模拟进程互斥

     

    实现临界区互斥的基本方法

     硬件实现方法

        通过硬件实现临界区最简单的办法就是关CPU的中断。从计算机原理我们知道,CPU进行进程切换是需要通过中断来进行。如果屏蔽了中断那么就可以保证当前进程顺利的将临界区代码执行完,从而实现了互斥。这个办法的步骤就是:屏蔽中断--执行临界区--开中断。但这样做并不好,这大大限制了处理器交替执行任务的能力。并且将关中断的权限交给用户代码,那么如果用户代码屏蔽了中断后不再开,那系统岂不是跪了?

        还有硬件的指令实现方式,这个方式和接下来要说的信号量方式如出一辙。但是通过硬件来实现,这里就不细说了。

     

    信号量实现方式

        这也是我们比较熟悉P V操作。通过设置一个表示资源个数的信号量S,通过对信号量S的P和V操作来实现进程的的互斥。

        P和V操作分别来自荷兰语Passeren和Vrijgeven,分别表示占有和释放。P V操作是操作系统的原语,意味着具有原子性。

        P操作首先减少信号量,表示有一个进程将占用或等待资源,然后检测S是否小于0,如果小于0则阻塞,如果大于0则占有资源进行执行。

        V操作是和P操作相反的操作,首先增加信号量,表示占用或等待资源的进程减少了1个。然后检测S是否小于0,如果小于0则唤醒等待使用S资源的其它进程。

        前面我们C#模拟进程的同步和互斥其实算是信号量进行实现的。

     

    一些经典利用信号量实现同步的问题

    生产者--消费者问题

        问题描述:生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。本作业要求设计在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来

     

        这里生产者和消费者是既同步又互斥的关系,首先只有生产者生产了,消费着才能消费,这里是同步的关系。但他们对于临界区的访问又是互斥的关系。因此需要三个信号量empty和full用于同步缓冲区,而mut变量用于在访问缓冲区时是互斥的。

        利用C#模拟生产者和消费者的关系如代码3所示。

        class ProducerAndCustomer
        {
            //临界区信号量
            private static Mutex mut = new Mutex();
    
            private static Semaphore empty = new Semaphore(5, 5);//空闲缓冲区
            private static Semaphore full = new Semaphore(0, 5);
            //生产者-消费者模拟
             static void Main()
             {
                 Console.WriteLine("生产者消费者模拟......");
                 for (int i = 1; i < 9; i++)
                 {
                     Thread Thread1 = new Thread(new ThreadStart(Producer));
                     Thread Thread2 = new Thread(new ThreadStart(Customer));
                     Thread1.Name = String.Format("生产者线程{0}", i);
                     Thread2.Name = String.Format("消费者线程{0}", i);
                     Thread1.Start();
                     Thread2.Start();
                 }
                 Console.ReadKey();
    
             }
             
             private static void Producer()
             {
                 Console.WriteLine("{0}已经启动",Thread.CurrentThread.Name);
                 empty.WaitOne();//对empty进行P操作
                 mut.WaitOne();//对mut进行P操作
                 Console.WriteLine("{0}放入数据到临界区", Thread.CurrentThread.Name);
                     Thread.Sleep(1000);
                 mut.ReleaseMutex();//对mut进行V操作
                 full.Release();//对full进行V操作
             }
             private static void Customer()
             {
                 Console.WriteLine("{0}已经启动", Thread.CurrentThread.Name);
                 Thread.Sleep(12000);
                 full.WaitOne();//对full进行P操作
                 mut.WaitOne();//对mut进行P操作
                 Console.WriteLine("{0}读取临界区", Thread.CurrentThread.Name);
                 mut.ReleaseMutex();//对mut进行V操作
                 empty.Release();//对empty进行V操作
             }
        }

       代码3.使用C#模拟生产者和消费者的关系

     

        运行结果如图5所示。

        5

         图5.生产者消费者C#模拟结果

     

    读者--写者问题

        问题描述:

          一个数据文件或记录,统称数据对象,可被多个进程共享,其中有些进程只要求读称为"读者",而另一些进程要求写或修改称为"写者"。

          规定:允许多个读者同时读一个共享对象,但禁止读者、写者同时访问一个共享对象,也禁止多个写者访问一个共享对象,否则将违反Bernstein并发执行条件。

        通过描述可以分析,这里的读者和写者是互斥的,而写者和写者也是互斥的,但读者之间并不互斥。

        由此我们可以设置3个变量,一个用来统计读者的数量,另外两个分别用于对读者数量读写的互斥,读者和读者写者和写者的互斥。如代码4所示。

    class ReaderAndWriter
        {
            private static Mutex mut = new Mutex();//用于保护读者数量的互斥信号量
            private static Mutex rw = new Mutex();//保证读者写者互斥的信号量
    
            static int count = 0;//读者数量
            
            
            static void Main()
            {
                Console.WriteLine("读者写者模拟......");
                for (int i = 1; i < 6; i++)
                {
    
                    Thread Thread1 = new Thread(new ThreadStart(Reader));
                    Thread1.Name = String.Format("读者线程{0}", i);
                    Thread1.Start();
                    
                }
                Thread Thread2 = new Thread(new ThreadStart(writer));
                Thread2.Name = String.Format("写者线程");
                Thread2.Start();
                Console.ReadKey();
    
    
            }
            
            private static void Reader()
            {
                
                mut.WaitOne();
                if (count == 0)
                {
                    rw.WaitOne();
                }
                count++;
                mut.ReleaseMutex();
                
                Thread.Sleep(new Random().Next(2000));//读取耗时1S
                Console.WriteLine("读取完毕");
                
                mut.WaitOne();
                count--;
                mut.ReleaseMutex();
                if (count == 0)
                {
                    rw.ReleaseMutex();
                }
    
            }
            private static void writer()
            {
                
                rw.WaitOne();
                Console.WriteLine("写入数据");
                rw.ReleaseMutex();
        
            }

       代码4.C#模拟读者和写者问题

     

        运行结果如图6所示。

        

        图6.读者写者的运行结果

     

    哲学家进餐问题

        问题描述:

        有五个哲学家,他们的生活方式是交替地进行思考和进餐。哲学家们公用一张圆桌,周围放有五把椅子,每人坐一把。在圆桌上有五个碗和五根筷子,当一个哲学家思考时,他不与其他人交谈,饥饿时便试图取用其左、右最靠近他的筷子,但他可能一根都拿不到。只有在他拿到两根筷子时,方能进餐,进餐完后,放下筷子又继续思考。

        8

        图7.哲学家进餐问题

     

        根据问题描述,五个哲学家分别可以看作是五个进程。五只筷子分别看作是五个资源。只有当哲学家分别拥有左右的资源时,才得以进餐。如果不指定规则,当每个哲学家手中只拿了一只筷子时会造成死锁,从而五个哲学家都因为吃不到饭而饿死。因此我们的策略是让哲学家同时拿起两只筷子。因此我们需要对每个资源设置一个信号量,此外,还需要使得哲学家同时拿起两只筷子而设置一个互斥信号量,如代码5所示。

    class philosopher
        {
            private static int[] chopstick=new int[5];//分别代表哲学家的5只筷子
            private static Mutex eat = new Mutex();//用于保证哲学家同时拿起两双筷子
            static void Main()
            {
                //初始设置所有筷子可用
                for (int k = 1; k <= 5; k++)
                {
                    chopstick[k - 1] = 1;
                }
                //每个哲学家轮流进餐一次
                for(int i=1;i<=5;i++)
                {
                    Thread Thread1 = new Thread(new ThreadStart(Philosophers));
                    Thread1.Name = i.ToString();
                    Thread1.Start();
                }
                Console.ReadKey();
            }
            private static void Philosophers()
            {
                
                //如果筷子不可用,则等待2秒
                while (chopstick[int.Parse(Thread.CurrentThread.Name)-1] !=1 || chopstick[(int.Parse(Thread.CurrentThread.Name))%4]!=1)
                {
                    Console.WriteLine("哲学家{0}正在等待", Thread.CurrentThread.Name);
                    Thread.Sleep(2000);
                }
                eat.WaitOne();
                //同时拿起两双筷子
                chopstick[int.Parse(Thread.CurrentThread.Name)-1] = 0;
                chopstick[(int.Parse(Thread.CurrentThread.Name)) % 4] = 0;
                eat.ReleaseMutex();
                Thread.Sleep(1000);
                Console.WriteLine("哲学家{0}正在用餐...",Thread.CurrentThread.Name);
                //用餐完毕后放下筷子
                chopstick[int.Parse(Thread.CurrentThread.Name)-1] = 1;
                chopstick[(int.Parse(Thread.CurrentThread.Name)) % 4] = 1;
                Console.WriteLine("哲学家{0}用餐完毕,继续思考", Thread.CurrentThread.Name);
            }
        }

        代码5.C#模拟哲学家用餐问题

     

        运行结果如图7所示。

        7

        图8.哲学家问题运行结果

     

     

    总结

        本文介绍了进程的同步和互斥的概念,临界区的概念,以及实现进程同步互斥的方式,并解决了3种实现同步的经典问题,并给出了相应的C#模拟代码。操作系统对于进程的管理是是计算机编程的基础之一,因此掌握这个概念会使你的内功更上一层:-D

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

     

    简介

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

     

    临界资源

        在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源)。但对于某些资源来说,其在同一时间只能被一个进程所占用。这些一次只能被一个进程所占用的资源就是所谓的临界资源。典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。

        对于临界资源的访问,必须是互诉进行。也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。而进程内访问临界资源的代码被成为临界区。

        对于临界区的访问过程分为四个部分:

        1.进入区:查看临界区是否可访问,如果可以访问,则转到步骤二,否则进程会被阻塞

        2.临界区:在临界区做操作

        3.退出区:清除临界区被占用的标志

        4.剩余区:进程与临界区不相关部分的代码

    临界资源使用规则:忙则等待、优先等待、空闲让进、让权等待(在临界区的进程,不能在临界区内长时间处于事件等待,必须在一定时间退出临界区)。

     多个进程常常需要共同修改某些共享变量、表格、文件数据库等,协作完成一些功能。共享协作带来了进程的同步和互斥、死锁、饥饿等问题。

    进程间同步和互诉的概念

     

    进程同步

        进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。

        比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。而当进程A产生信息放入缓冲区时,进程B才会被唤醒。概念如图1所示。

        1

         图1.进程之间的同步

     

    进程互斥

        进程互斥是进程之间的间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。

        比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。概念如图3所示。

        3

         图3.进程之间的互斥

     

     

    实现临界区互斥的基本方法

     软件方法

    Dekker算法和peterson算法

     

     硬件实现方法

        通过硬件实现临界区最简单的办法就是关CPU的中断。从计算机原理我们知道,CPU进行进程切换是需要通过中断来进行。如果屏蔽了中断那么就可以保证当前进程顺利的将临界区代码执行完,从而实现了互斥。这个办法的步骤就是:屏蔽中断--执行临界区--开中断。但这样做并不好,这大大限制了处理器交替执行任务的能力。并且将关中断的权限交给用户代码,那么如果用户代码屏蔽了中断后不再开,那系统岂不是跪了?

        还有硬件的指令实现方式,这个方式和接下来要说的信号量方式如出一辙。但是通过硬件来实现,这里就不细说了。

     

    信号量实现方式

        这也是我们比较熟悉P V操作。通过设置一个表示资源个数的信号量S,通过对信号量S的P和V操作来实现进程的的互斥。

        P和V操作分别来自荷兰语Passeren和Vrijgeven,分别表示占有和释放。P V操作是操作系统的原语,意味着具有原子性。

        P操作首先减少信号量,表示有一个进程将占用或等待资源,然后检测S是否小于0,如果小于0则阻塞,如果大于0则占有资源进行执行。

        V操作是和P操作相反的操作,首先增加信号量,表示占用或等待资源的进程减少了1个。然后检测S是否小于0,如果小于0则唤醒等待使用S资源的其它进程。

        前面我们C#模拟进程的同步和互斥其实算是信号量进行实现的。

     

    一些经典利用信号量实现同步的问题

    生产者--消费者问题

        问题描述:生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。本作业要求设计在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来

     

        这里生产者和消费者是既同步又互斥的关系,首先只有生产者生产了,消费着才能消费,这里是同步的关系。但他们对于临界区的访问又是互斥的关系。因此需要三个信号量empty和full用于同步缓冲区,而mut变量用于在访问缓冲区时是互斥的。

     

     

    读者--写者问题

        问题描述:

          一个数据文件或记录,统称数据对象,可被多个进程共享,其中有些进程只要求读称为"读者",而另一些进程要求写或修改称为"写者"。

          规定:允许多个读者同时读一个共享对象,但禁止读者、写者同时访问一个共享对象,也禁止多个写者访问一个共享对象,否则将违反Bernstein并发执行条件。

     

        通过描述可以分析,这里的读者和写者是互斥的,而写者和写者也是互斥的,但读者之间并不互斥。

        由此我们可以设置3个变量,一个用来统计读者的数量,另外两个分别用于对读者数量读写的互斥,读者和读者写者和写者的互斥。如代码4所示。

     

     

     

    哲学家进餐问题

        问题描述:

        有五个哲学家,他们的生活方式是交替地进行思考和进餐。哲学家们公用一张圆桌,周围放有五把椅子,每人坐一把。在圆桌上有五个碗和五根筷子,当一个哲学家思考时,他不与其他人交谈,饥饿时便试图取用其左、右最靠近他的筷子,但他可能一根都拿不到。只有在他拿到两根筷子时,方能进餐,进餐完后,放下筷子又继续思考。

        8

        图7.哲学家进餐问题

     

        根据问题描述,五个哲学家分别可以看作是五个进程。五只筷子分别看作是五个资源。只有当哲学家分别拥有左右的资源时,才得以进餐。如果不指定规则,当每个哲学家手中只拿了一只筷子时会造成死锁,从而五个哲学家都因为吃不到饭而饿死。因此我们的策略是让哲学家同时拿起两只筷子。因此我们需要对每个资源设置一个信号量,此外,还需要使得哲学家同时拿起两只筷子而设置一个互斥信号量,如代码5所示。

     

     

     

    总结

        本文介绍了进程的同步和互斥的概念,临界区的概念,以及实现进程同步互斥的方式,并解决了3种实现同步的经典问题,并给出了相应的C#模拟代码。操作系统对于进程的管理是是计算机编程的基础之一,因此掌握这个概念会使你的内功更上一层:-D

     

    C++代码实现生产者消费者问题

    #include <iostream>
    using namespace std;

    int const buffersize = 5;
    /* 定义进程控制块PCB */
    struct PCB 

    int flag; //flag=1 denote producer;flag=2 denote consumer;
    int numlabel;
    char product;
    char state;
    struct PCB* processlink; process link pointer
    }*exe=0,*over=0;

    PCB * readyhead = 0, * readytail = 0; /ready queue;
    PCB * consumerhead = 0,* consumertail = 0;/consumer queue;
    PCB * producerhead = 0,* producertail = 0;//producer queue;

    int productnum=0; //产品数量
    int processnum=0; //进程数
    int full=0,empty=buffersize; // semaphore

    char buffer[buffersize]; //缓冲区
    int bufferpoint=0; //缓冲区指针

    void linkqueue( PCB* process, PCB* & tail ); 
    PCB* getp(PCB* head, PCB* & tail);
    int hasElement(PCB* pro);
    void display(PCB* p);
    void linklist(PCB* p,PCB* listhead);
    void freelink(PCB* linkhead);
    int processproc(); 
    int waitfull();
    int waitempty();
    void signalempty();
    void signalfull();
    void producerrun();
    void comsuerrun();

    int main()

    char begin;
    int element;
    cout<<"你想开始程序吗?(y/n)"; 
    cin>>begin; 
    producerhead = new PCB;
    if( !producerhead ) return 1;
    producertail = producerhead;
    producerhead->processlink = 0;
    producerhead->flag = 1;
    producerhead->numlabel = processnum;

    consumerhead = new PCB;
    if( !consumerhead ) return 1;
    consumertail = consumerhead;
    consumerhead->processlink = 0;
    consumerhead->flag = 2;
    consumerhead->numlabel = processnum;

    readyhead = new PCB; 
    if( !readyhead ) return 1;
    readytail = readyhead;
    readyhead->processlink = 0;
    readyhead->flag = 3; 
    readyhead->numlabel = processnum;

    over = new PCB;
    if ( !over ) return 1;
    over->processlink = 0;
    while( begin=='y') 

    if( !processproc() ) break;/
    element = hasElement( readyhead );

    while( element )
    {
    exe = getp( readyhead,readytail );
    printf("进程%d申请运行,它是一个",exe->numlabel);
    exe->flag==1? printf("生产者\n"):printf("消费者\n");
    if( exe->flag==1 )
    producerrun( ); 
    /* comsuerrun( ); */
    else
    comsuerrun( );

    element = hasElement(readyhead); 
    }

    cout<<"就绪队列中无进程"<<endl;

    if( hasElement(consumerhead) )

    cout<<"消费者等待队列中有进程:"<<endl;
    display( consumerhead );
    }
    else 
    {
    cout<<"消费者等待队列中已无进程!"<<endl;
    }

    if(hasElement(producerhead))

    cout<<"生产者等待队列中有进程:"<<endl;
    display( producerhead );
    }
    else 
    {
    cout<<"生产者等待队列中已无进程!"<<endl;
    }

    cout<<"\n你想继续吗?(press /'y/' for /'n/')";
    cin>>begin;
    }

    cout<<"\n 进程模拟完成."<<endl; 
    freelink(over);
    over = 0;

    freelink(readyhead);
    readyhead = 0;
    readytail = 0;

    freelink(consumerhead);
    consumerhead = 0;
    consumertail = 0;

    freelink(producerhead);
    producerhead = 0;
    producertail = 0;

    return 0;
    }

     


    void linkqueue( PCB* process, PCB* & tail ) /将进程process插入到队列尾部
    {
    if( tail )
    {
    tail->processlink = process;
    tail = process;

    }
    else
    {
    cout<<"队列未初始化!"; 
    exit(1);

    }

    PCB* getp(PCB* head,PCB* & tail)//获取进程链表首元素
    {
    PCB* p;
    p = head->processlink;
    if( p )
    {
    head->processlink = p->processlink; 
    p->processlink = 0; 
    if( !head->processlink ) 
    tail = head;
    }

    else 
    return 0;

    return p;

    }


    int processproc( ) 
    {
    int flag,num;
    char ch;
    PCB* p = 0;

    cout<<"\n 请输入希望产生的进程个数:"; 
    cin>>num;

    for(int i=0;i<num;i++) 
    {
    cout<<"\n 请输入您要产生的进程:输入1为生产者进程;输入2为消费者进程\n";
    cin>>flag;

    p = new PCB;
    if( !p ) 
    {
    cout<<"内存分配失败!"<<endl;
    return 0;
    }

    p->flag = flag;
    processnum++;
    p->numlabel = processnum;
    p->processlink = 0;

    if( p->flag == 1 )
    {
    printf("您要产生的是生产者进程,它是第%d个进程,请输入您要该进程产生的字符:\n",processnum);
    cin>>ch;
    p->product=ch;
    productnum++;
    printf("您要该进程产生的字符是%c \n",p->product);
    }
    else 
    {
    printf("您要产生的是消费者进程,它是第%d个进程。\n",p->numlabel);
    }

    linkqueue( p , readytail);
    }

    return 1;
    }

    void signalempty( ) //生产者队列中有数据就放到就绪队列中,无数据空数据加一
    {
    PCB* p; 
    if( hasElement(producerhead) ) 
    {
    p = getp( producerhead,producertail );
    linkqueue( p, readytail ); 
    printf("等待中的生产者进程进入就绪队列,它的进程号是%d\n",p->numlabel);
    }
    empty++; 
    }

    void signalfull( )/消费者队列中有数据就放到就绪队列中(有无数据时)消费者进程数目full+1
    {
    PCB* p; 
    if( hasElement(consumerhead) )
    {
    p = getp(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;
    //int var = bufferpoint;
    //for (int i =0; i<var; i++)
    //{
    // printf("进程%d开始从缓冲区取数\n",exe->numlabel);
    // exe->product = buffer[bufferpoint-1];
    // bufferpoint--;
    // exe->product = buffer[i];
    // printf("进程%d从缓冲区取数操作结束,取数是%c\n",exe->numlabel,exe->product);
    // signalempty();
    // linklist( exe, over );
    //}

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

    p->flag==1? printf("生产者进程"):printf("消费者进程");
    printf("%d\n",p->numlabel);
    p = p->processlink;
    }
    }


    int hasElement(PCB* pro)//判读是否有进程
    {
    if( !pro->processlink )
    return 0;
    else 
    return 1;
    }

    int waitempty()消费者消费(完了)生成者产生的数据,值0,运行进程进入生成者等待队列
    {
    if(empty<=0 )
    {
    printf("进程%d:缓冲区存数,缓冲区满,该进程进入生产者等待队列\n",exe->numlabel); 
    linkqueue( exe, producertail );
    return 0;
    }
    else

    empty--;
    return 1;
    }
    }

    int waitfull() 生成者生成数据填满,进程进入消费者等待队列;
    {
    if(full<=0)
    {
    printf("进程%d:缓冲区取数,缓冲区空,该进程进入消费者等待队列\n",exe->numlabel);
    linkqueue( exe, consumertail );
    return 0;
    }
    else

    full--;
    return 1;
    }
    }

    void linklist(PCB* p,PCB* listhead) 把进程p追加到listhead链表之后 
    {
    PCB* cursor = listhead;
    while( cursor->processlink )
    {
    cursor = cursor->processlink;
    }
    cursor->processlink = p;
    }

    void freelink(PCB* linkhead) 
    {
    PCB* p;
    while( linkhead )
    {
    p = linkhead;
    linkhead = linkhead->processlink;
    delete(p);
    }
    }

    博客

    展开全文
  • 1.1 进程同步和互斥的基本概念 在多道程序环境下,操作系统必须采取相应措施处理好进程之间的制约关系。 进程同步的主要任务是对多个有制约关系的进程在执行次序上进行协调,以使并发进程间能有效地、安全地互相...
  • 操作系统——进程同步互斥

    千次阅读 2019-10-21 22:13:19
    文章目录进程同步互斥简介进程间合作进程间合作的问题竞争条件原子操作临界区相关的几个概念忙等待的互斥基于硬件的同步解决办法:屏蔽中断基于软件的同步解决方法严格轮换法Peterson解法N线程的软件方法基于软件...
  • 为了协调进程之间的相互制约关系,引入了进程同步概念。 临界资源 虽然多个进程可以共享系统中的各种资源,但其中许多资源一次只能为一个进程所使用,我们把一次仅允许一个进程使用的资源称为临界资源。许多物理...
  • 在讨论如何用信号量机制解决这个问题之前,我们应该先了解进程同步和互斥间的一些概念。 首先是进程间的两种关系:同步和互斥。所谓同步就是把异步环境下的一组并发进程,因直接制约而互相发送消息二进行互相合作、...
  • 进程同步互斥概念原理

    千次阅读 2018-07-17 11:56:56
    进程同步是一个操作系统级别的概念,是在多道程序的环境下,存在着不同的制约关系,为了协调这种互相制约的关系,实现资源共享进程协作,从而避免进程之间的冲突,引入了进程同步。 临界资源 在操作系统中,...
  • 进程同步互斥

    2020-06-01 22:53:38
    进程同步概念:亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作。 进程互斥...
  • 进程同步是一个操作系统级别的概念,是在多道程序的环境下,存在着不同的制约关系,为了协调这种互相制约的关系,实现资源共享进程协作,从而避免进程之间的冲突,引入了进程同步。 临界资源 在操作系统中,进程是...
  • 进程同步互斥

    2018-03-27 15:57:31
    进程同步是一个操作系统级别的概念,是在多道程序的环境下,存在着不同的制约关系,为了协调这种互相制约的关系,实现资源共享进程协作,从而避免进程之间的冲突,引入了进程同步。而互斥和同步之间存在联系所以,...
  • 文章目录进程同步互斥、信号量机制一、进程同步、进程互斥概念1.1 进程同步1.2 进程互斥二、进程互斥的实现方法2.1 进程互斥的软件实现方法2.2 进程互斥的硬件实现方法三、信号量机制*3.1 信号量机制的概念3.2 ...
  • 文章目录什么是进程同步什么是进程互斥进程同步实现方式进程互斥的实现方式 什么是进程同步 知识点回顾:进程是具有异步性的特征。 异步性是指,各并发执行的进程以各自独立的、不可预知的速度向前推进。 读进程写...
  • (1)实验报告中要包含完成此题目所查阅的一些关键技术材料,例如,进程同步和互斥基本概念,信号量解决互斥的基本方法等。; (2)报告中有实现的关键技术点源代码,源代码书写要有一定的规范,源代码中有相关的...
  • 进程同步互斥基础

    千次阅读 2013-11-02 15:07:53
    同步:为了完成某个任务而建立的两个或多个进程,这些进程为了需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系。进程间的制约关系就是源于它们之间的相互合作。 互斥:当一个进程进入临界区...
  • 进程同步互斥笔记

    千次阅读 2017-03-16 23:36:19
    1、进程之间的两种相互制约关系(1)间接相互制约关系(互斥关系)同处于一个系统中的进程,通常都共享着某种资源,如共享CPU、共享I/O设备等,所谓间接相互制约即源于这种资源共享,使系统中本来没有关系的进程因...
  • 什么是进程同步 进程互斥的原则 进程互斥的软件实现方法 1、单标志法 2、双标志先检查法 3、双标志后检查法 4、Peterson 算法 进程互斥的硬件实现方法 1、中断屏蔽方法 2、TestAndSetLock 指令 TSL中断屏蔽的区别 ...
  • 1.进程同步互斥的区别? 互斥:某一资源同时只允许一个访问者对其进行访问,具有唯一性排它性。互斥无法限制访问者对资源的访问顺序即访问时无序的。如:接学家就餐问题,每个人手中只有一个筷子。 同步:基于...
  • 2.理解生产者消费者模型,了解其它典型的同步互斥模型,如哲学家就餐、读者-写者模型等。 3.学习使用Windows中基本的同步对象,掌握相关API的使用方法。 4.了解Windows中多线程的并发执行机制,实现进程的同步与...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 47,057
精华内容 18,822
关键字:

进程同步和互斥的概念