操作系统线程同步之生产者---消费者问题

生产者-消费者问题 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。解决生产者 / 消费者问题的方法可分为两类:(1)采用某种机制保护生产者和消费者之间的同步;(2)在生产者和消费者之间建立一个管道。第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式。第二种管道缓冲区不易控制,被传输数据对象不易于封装等... 阅读详情

生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。

阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。

在这里插入图片描述

wait/notify方法

首先,我们搞清楚Thread.sleep()方法和Object.wait()、Object.notify()方法的区别。

sleep()是Thread类的方法;而wait(),notify(),notifyAll()是Object类中定义的方法;尽管这两个方法都会影响线程的执行行为,但是本质上是有区别的。

Thread.sleep()不会导致锁行为的改变,如果当前线程是拥有锁的,那么Thread.sleep()不会让线程释放锁。如果能够帮助你记忆的话,可以简单认为和锁相关的方法都定义在Object类中,因此调用Thread.sleep()是不会影响锁的相关行为。

Thread.sleep和Object.wait都会暂停当前的线程,对于CPU资源来说,不管是哪种方式暂停的线程,都表示它暂时不再需要CPU的执行时间。OS会将执行时间分配给其它线程。区别是调用wait后,需要别的线程执行notify/notifyAll才能够重新获得CPU执行时间。

线程状态图:

在这里插入图片描述

  • Thread.sleep()让线程从 【running】 -> 【阻塞态】 时间结束/interrupt -> 【runnable】
  • Object.wait()让线程从 【running】 -> 【等待队列】notify -> 【锁池】 -> 【runnable】

实现生产者消费者模型

生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。在Java中一共有四种方法支持同步,其中前三个是同步方法,一个是管道方法。

(1)Object的wait() / notify()方法
(2)Lock和Condition的await() / signal()方法
(3)BlockingQueue阻塞队列方法
(4)PipedInputStream / PipedOutputStream

1. 使用Object的wait() / notify()方法

wait()/ nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。

  • wait():当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。
  • notify():当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
/**
 * 生产者消费者模式:使用Object.wait() / notify()方法实现
 */
public class ProducerConsumer {
    private static final int CAPACITY = 5;

    public static void main(String args[]){
        Queue<Integer> queue = new LinkedList<Integer>();

        Thread producer1 = new Producer("P-1", queue, CAPACITY);
        Thread producer2 = new Producer("P-2", queue, CAPACITY);
        Thread consumer1 = new Consumer("C1", queue, CAPACITY);
        Thread consumer2 = new Consumer("C2", queue, CAPACITY);
        Thread consumer3 = new Consumer("C3", queue, CAPACITY);

        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        consumer3.start();
    }

    /**
     * 生产者
     */
    public static class Producer extends Thread{
        private Queue<Integer> queue;
        String name;
        int maxSize;
        int i = 0;

        public Producer(String name, Queue<Integer> queue, int maxSize){
            super(name);
            this.name = name;
            this.queue = queue;
            this.maxSize = maxSize;
        }

        @Override
        public void run(){
            while(true){
                synchronized(queue){
                    while(queue.size() == maxSize){
                        try {
                            System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue.");
                            queue.wait();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                    System.out.println("[" + name + "] Producing value : +" + i);
                    queue.offer(i++);
                    queue.notifyAll();

                    try {
                        Thread.sleep(new Random().nextInt(1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    /**
     * 消费者
     */
    public static class Consumer extends Thread{
        private Queue<Integer> queue;
        String name;
        int maxSize;

        public Consumer(String name, Queue<Integer> queue, int maxSize){
            super(name);
            this.name = name;
            this.queue = queue;
            this.maxSize = maxSize;
        }

        @Override
        public void run(){
            while(true){
                synchronized(queue){
                    while(queue.isEmpty()){
                        try {
                            System.out.println("Queue is empty, Consumer[" + name + "] thread is waiting for Producer");
                            queue.wait();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                    int x = queue.poll();
                    System.out.println("[" + name + "] Consuming value : " + x);
                    queue.notifyAll();

                    try {
                        Thread.sleep(new Random().nextInt(1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
package Demo;

import java.util.LinkedList;
import java.util.Queue;

public class ThreadDemo {

	private final int maxSize=5;
	private final int minSize=0;
	private Queue<Integer> que=new LinkedList<Integer>();
	
	public static void main(String[] args)
	{
		ThreadDemo t=new ThreadDemo();
		Thread a=t.new A();
		Thread b=t.new B();
		
		a.start();
		b.start();
	}
	
	class A extends Thread{
		
		public void run()
		{
			a();
		}
		
		public synchronized void a()
		{
			while(true)
			{
				synchronized(que)
				{
					while(que.size()>=maxSize)
					{
						try {
							System.out.println("is maxSize,stop");
							que.wait();
						} catch (Exception e) {
							// TODO: handle exception
							e.printStackTrace();
						}
						
					}
					que.offer(1);
					que.notifyAll();
					System.out.println("add one");
					try {
						sleep(500);
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
			}
		}
	}
	
	class B extends Thread{
		
		public void run()
		{
			b();
		}
		
		public synchronized void b()
		{
			while(true)
			{
				synchronized(que)
				{
					while(que.size()==minSize)
					{
						try {
							System.out.println("is minSize,null");
							que.wait();
						} catch (Exception e) {
							// TODO: handle exception
							e.printStackTrace();
						}
						
					}
					que.poll();
					que.notifyAll();
					System.out.println("remove one");
					try {
						sleep(500);
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
			}
		}
	}
}
注意要点

判断Queue大小为0或者大于等于queueSize时须使用 while (condition) {},不能使用 if(condition) {}。其中 while(condition)循环,它又被叫做“自旋锁”。自旋锁以及wait()和notify()方法在线程通信这篇文章中有更加详细的介绍。为防止该线程没有收到notify()调用也从wait()中返回(也称作虚假唤醒),这个线程会重新去检查condition条件以决定当前是否可以安全地继续执行还是需要重新保持等待,而不是认为线程被唤醒了就可以安全地继续执行了。

2. 使用Lock和Condition的await() / signal()方法

在JDK5.0之后,Java提供了更加健壮的线程处理机制,包括同步、锁定、线程池等,它们可以实现更细粒度的线程控制。Condition接口的await()和signal()就是其中用来做同步的两种方法,它们的功能基本上和Object的wait()/ nofity()相同,完全可以取代它们,但是它们和新引入的锁定机制Lock直接挂钩,具有更大的灵活性。通过在Lock对象上调用newCondition()方法,将条件变量和一个锁对象进行绑定,进而控制并发程序访问竞争资源的安全。下面来看代码:

/**
 * 生产者消费者模式:使用Lock和Condition实现
 * {@link java.util.concurrent.locks.Lock}
 * {@link java.util.concurrent.locks.Condition}
 */
public class ProducerConsumerByLock {
    private static final int CAPACITY = 5;
    private static final Lock lock = new ReentrantLock();
    private static final Condition fullCondition = lock.newCondition();     //队列满的条件
    private static final Condition emptyCondition = lock.newCondition();        //队列空的条件


    public static void main(String args[]){
        Queue<Integer> queue = new LinkedList<Integer>();

        Thread producer1 = new Producer("P-1", queue, CAPACITY);
        Thread producer2 = new Producer("P-2", queue, CAPACITY);
        Thread consumer1 = new Consumer("C1", queue, CAPACITY);
        Thread consumer2 = new Consumer("C2", queue, CAPACITY);
        Thread consumer3 = new Consumer("C3", queue, CAPACITY);

        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        consumer3.start();
    }

    /**
     * 生产者
     */
    public static class Producer extends Thread{
        private Queue<Integer> queue;
        String name;
        int maxSize;
        int i = 0;

        public Producer(String name, Queue<Integer> queue, int maxSize){
            super(name);
            this.name = name;
            this.queue = queue;
            this.maxSize = maxSize;
        }

        @Override
        public void run(){
            while(true){

                //获得锁
                lock.lock();
                while(queue.size() == maxSize){
                    try {
                        System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue.");
                        //条件不满足,生产阻塞
                        fullCondition.await();
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
                System.out.println("[" + name + "] Producing value : +" + i);
                queue.offer(i++);

                //唤醒其他所有生产者、消费者
                fullCondition.signalAll();
                emptyCondition.signalAll();

                //释放锁
                lock.unlock();

                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    /**
     * 消费者
     */
    public static class Consumer extends Thread{
        private Queue<Integer> queue;
        String name;
        int maxSize;

        public Consumer(String name, Queue<Integer> queue, int maxSize){
            super(name);
            this.name = name;
            this.queue = queue;
            this.maxSize = maxSize;
        }

        @Override
        public void run(){
            while(true){
                //获得锁
                lock.lock();

                while(queue.isEmpty()){
                    try {
                        System.out.println("Queue is empty, Consumer[" + name + "] thread is waiting for Producer");
                        //条件不满足,消费阻塞
                        emptyCondition.await();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                int x = queue.poll();
                System.out.println("[" + name + "] Consuming value : " + x);

                //唤醒其他所有生产者、消费者
                fullCondition.signalAll();
                emptyCondition.signalAll();

                //释放锁
                lock.unlock();

                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
3. 使用BlockingQueue阻塞队列方法

JDK 1.5 以后新增的 java.util.concurrent包新增了 BlockingQueue 接口。并提供了如下几种阻塞队列实现:

  • java.util.concurrent.ArrayBlockingQueue
  • java.util.concurrent.LinkedBlockingQueue
  • java.util.concurrent.SynchronousQueue
  • java.util.concurrent.PriorityBlockingQueue
    实现生产者-消费者模型使用 ArrayBlockingQueue或者 LinkedBlockingQueue即可。

我们这里使用LinkedBlockingQueue,它是一个已经在内部实现了同步的队列,实现方式采用的是我们第2种await()/ signal()方法。它可以在生成对象时指定容量大小。它用于阻塞操作的是put()和take()方法。

  • put()方法:类似于我们上面的生产者线程,容量达到最大时,自动阻塞。
  • take()方法:类似于我们上面的消费者线程,容量为0时,自动阻塞。

我们可以跟进源码看一下LinkedBlockingQueue类的put()方法实现:

/** Main lock guarding all access */
final ReentrantLock lock = new ReentrantLock();

/** Condition for waiting takes */
private final Condition notEmpty = lock.newCondition();

/** Condition for waiting puts */
private final Condition notFull = lock.newCondition();



public void put(E e) throws InterruptedException {
    putLast(e);
}

public void putLast(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    Node<E> node = new Node<E>(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        while (!linkLast(node))
            notFull.await();
    } finally {
        lock.unlock();
    }
}

看到这里证实了它的实现方式采用的是我们第2种await()/ signal()方法。下面我们就使用它实现吧。

/**
 * 生产者消费者模式:使用{@link java.util.concurrent.BlockingQueue}实现
 */
public class ProducerConsumerByBQ{
    private static final int CAPACITY = 5;

    public static void main(String args[]){
        LinkedBlockingDeque<Integer> blockingQueue = new LinkedBlockingDeque<Integer>(CAPACITY);

        Thread producer1 = new Producer("P-1", blockingQueue, CAPACITY);
        Thread producer2 = new Producer("P-2", blockingQueue, CAPACITY);
        Thread consumer1 = new Consumer("C1", blockingQueue, CAPACITY);
        Thread consumer2 = new Consumer("C2", blockingQueue, CAPACITY);
        Thread consumer3 = new Consumer("C3", blockingQueue, CAPACITY);

        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        consumer3.start();
    }

    /**
     * 生产者
     */
    public static class Producer extends Thread{
        private LinkedBlockingDeque<Integer> blockingQueue;
        String name;
        int maxSize;
        int i = 0;

        public Producer(String name, LinkedBlockingDeque<Integer> queue, int maxSize){
            super(name);
            this.name = name;
            this.blockingQueue = queue;
            this.maxSize = maxSize;
        }

        @Override
        public void run(){
            while(true){
                try {
                    blockingQueue.put(i);
                    System.out.println("[" + name + "] Producing value : +" + i);
                    i++;

                    //暂停最多1秒
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    /**
     * 消费者
     */
    public static class Consumer extends Thread{
        private LinkedBlockingDeque<Integer> blockingQueue;
        String name;
        int maxSize;

        public Consumer(String name, LinkedBlockingDeque<Integer> queue, int maxSize){
            super(name);
            this.name = name;
            this.blockingQueue = queue;
            this.maxSize = maxSize;
        }

        @Override
        public void run(){
            while(true){
                try {
                    int x = blockingQueue.take();
                    System.out.println("[" + name + "] Consuming : " + x);

                    //暂停最多1秒
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
4. PipedInputStream / PipedOutputStream

这个类位于java.io包中,是解决同步问题的最简单的办法,一个线程将数据写入管道,另一个线程从管道读取数据,这样便构成了一种生产者/消费者的缓冲区编程模式。PipedInputStream/PipedOutputStream只能用于多线程模式,用于单线程下可能会引发死锁

package test;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class Hosee {
    final PipedInputStream pis = new PipedInputStream();
    final PipedOutputStream pos = new PipedOutputStream();
    {
        try {
            pis.connect(pos);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            try{
                while(true){
                    int b = (int) (Math.random() * 255);
                    System.out.println("Producer: a byte, the value is " + b);
                    pos.write(b);
                    pos.flush();
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                try{
                    pos.close();
                    pis.close();
                }catch(IOException e){
                    System.out.println(e);
                }
            }
        }
    }

    class Consumer implements Runnable {

        @Override
        public void run() {
            try{
                while(true){
                    int b = pis.read();
                    System.out.println("Consumer: a byte, the value is " + String.valueOf(b));
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                try{
                    pos.close();
                    pis.close();
                }catch(IOException e){
                    System.out.println(e);
                }
            }
        }

    }

    public static void main(String[] args) throws Exception {
        Hosee hosee = new Hosee();
        new Thread(hosee.new Producer()).start();
        new Thread(hosee.new Consumer()).start();
    }

}
【操作系统】多线程同步与互斥 【实验内容】(1)编写程序,使用Linux操作系统中的信号量机制模拟实现生产者-消费者问题。设有一个生产者和一个消费者,缓冲区可以存放产品,生产者不断生成产品放入缓冲区,消费者不断从缓冲区中取出产品,消费产品。(2)以上实验只模拟了一个产品的放入与取出,请修改代码,以模拟实现多个产品的放入与取出。 阅读详情

相关推荐

操作系统:生产者-消费者问题的多线程同步解决方案

本文还有配套的精品资源,点击获取 简介:操作系统作为计算机科学的核心课程,负责管理计算机资源。本压缩包内含燕山大学操作系统课程的第三次作业,专注于解决生产者-消费者问题。该问题描述了多线程环境下的数据共享与同步,其中生产者线程生成数据,消费者线程处理数据。为防止系统错误,需实现线程同步机制,如信号量和互斥锁。本作业解决方案可能涉及信号量的使用来控制缓冲区访问,互斥锁来保护共...

weixin_42437253的博客 1133

操作系统 | PV操作七大经典问题 生产者消费者 读者写者 哲学家进餐 理发师理发睡觉 和尚打水 吸烟者 吃水果

在生产者 - 消费者问题中, 如果缓冲区大小为 1 , 那么有可能不需要设置互斥信号量就可以实现 互斥访问缓冲区的功能。当然, 这不是绝对的, 要具体问题具体分析。建议: 在考试中如果来不及仔细分析, 可以加上互斥信号量, 保证各进程一定会互斥地访问缓冲区。但 需要注意的是, 实现互斥的P操作一定要在实现同步的P操作之后, 否则可能 引起 “ 死锁。

"You are worthy! You can do it!" 1万+

操作系统实践:生产者消费者问题课程设计

进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。进程由程序、数据和进程控制块(PCB)组成。PCB是进程存在的唯一标志,包含了进程标识符、状态、优先级、程序计数器、寄存器集合、内存管理信息以及记账信息等。程序:静态的代码部分,存储在硬盘等非易失性存储介质上。数据:程序运行时需要的数据和资源,通常存储在内存中。进程控制块(PCB):包含操作系统管理和控制进程所需的全部信息。进程具有以下属性:并发性。

weixin_42451850的博客 1084

多线程的同步问题的经典案例生产者-消费者模式剖析

生产者-消费者问题(Producer-Consumer Problem)也称有限缓冲问题(Bounded-Buffer Problem),是一个多线程同步问题的经典案例。 生产者-消费者问题描述了两个访问共享缓冲区的线程,即生产者线程和消费者线程,在实际运行时会发生的问题。生产者线程的主要功能是生成一定量的数据放到缓冲区中,然后重复此过程。消费者线程的主要功能是从缓冲区提取(或消耗)数据。

唐欢 1411

Transformer模型详解(图解最完整版)

Transformer由论文提出,现在是谷歌云TPU推荐的参考模型。论文相关的Tensorflow的代码可以从GitHub获取,其作为Tensor2Tensor包的一部分。哈佛的NLP团队也实现了一个基于PyTorch的版本,并注释该论文。在本文中,我们将试图把模型简化一点,并逐一介绍里面的核心概念,希望让普通读者也能轻易理解。Transformer 与 RNN 不同,可以比较好地并行训练。

2501_91695094的博客 2700

SAP-ML章<<<<第二节:物料账报错处理ABAP编程错误:RAISE_EXCEPTION>>>>

#SAP-ML章<<<<第一节:物料账报错处理ABAP编程错误:RAISE_EXCEPTION>>>> 1.物料账报错提示: ABAP编程错误:RAISE_EXCEPTION ABAP程序:SAPLFCML4H_RUN_PRICES应用组件CO-PC-ACT 2. 物料账报错背景: CKMLCP运行结算时 3. 解决方案: 通过DEBUG查看错误的地方 OKTZ:分析原因为:可能打包或者配置传输时弄错 ...

SAP.David.Gao的博客 1856

【JUC基础】06. 生产者和消费者问题

学习JUC,就不得不提生产者消费者。生产者消费者模型是一种经典的多线程模型,用于解决生产者和消费者之间的数据交换问题。在生产者消费者模型中,生产者生产数据放入共享的缓冲区中,消费者从缓冲区中取出数据进行消费。在这个过程中,生产者和消费者之间需要保持同步,以避免数据出现错误或重复。今天我们就来说说生产者消费者模型,以及JUC中如何解决该模型的同步问题。

有一只柴犬的专栏 1207

手把手教你用gmid方法设计二级运放:从理论到仿真全流程(附避坑指南)

本文详细介绍了使用gmid方法设计二级运放的全流程,从理论到仿真实践,特别针对初学者常见问题提供避坑指南。通过系统化的晶体管尺寸确定技术,帮助工程师在性能、功耗和面积之间找到最佳平衡点,适用于模拟集成电路设计中的关键模块开发。

weixin_29213525的博客 271

线程同步-生产者消费者问题

在进行多线程编程时,难免还要碰到两个问题,那就线程间的互斥与同步: 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。 线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放

big_bit的博客 1万+

【YOLO11改进 - C3k2融合】C3k2融合AKConv(可改变核卷积)二次创新:任意数量的参数和任意采样形状的即插即用的卷积

【YOLO11改进 - C3k2融合】C3k2融合AKConv(可改变核卷积)二次创新:任意数量的参数和任意采样形状的即插即用的卷积

专注于图像领域,主要研究内容包括计算机视觉和深度学习,特别是在图像分类、目标检测和图像生成等方面有深入的研究和实践经验。 407

YOLOv5入门实践(2)——手把手教你利用labelimg标注数据集

YOLOv5入门实践第2步,手把手教你使用labelimg标注数据集

路人贾的博客 1万+

生产者消费者问题操作系统_多线程中的生产者消费者问题 线程的同步

同步问题的提出操作系统中的生产者消费者问题,就是一个经典的同步问题。举一个例子,有两个人,一个人在刷盘子,另一个人在烘干。这两个人各自代表一个线程,他们之间有一个共享的对象 --- 盘架,刷好而等待烘干的盘子放在盘架上。两个人在没有事做事都愿意歇着。显然,盘架上有刷好的盘子时,烘干的人才能开始工作;而如果刷盘子的人刷的太快,刷好的盘子占满了盘架时,他就不能再继续工作了,而要等到盘架上...

weixin_29486701的博客 311

MISRA C 详解 · 专栏06:2023 与 2025 更新总览(相对 2012 的差异)

本专栏 01~05 篇基于(143 规则 + 16 指令)。这六年间标准又前进了两步——(大改)和(微调)。本文补充说明「相对 2012,标准变在哪」,并给出新增规范的代表性示例。

XavierKong的博客 73

操作系统03——生产者消费者线程同步问题实验

主要任务 采用条件变量和互斥锁实现生产者消费者线程同步 一、生产者消费者问题 生产者进程生产产品,将产品提供给消费者进程消费。 在两者之间设置有缓冲区,生产者将产品放入缓冲区,消费者从缓冲区中取走产品。 两者之间需要保持同步,消费者不可以从空的缓冲区中取产品,生产者进程也不可以向已经装满产品的缓冲区投放产品。 二、问题分析 可以用一个数组buffer[n]来表示大小为n的缓冲区。 每当投入一个产品时,buffer中的数组单元指针in加1 每当取出一个产品时,buffer中的数组单元指针out加1 由于buf

winterjojo的博客 3268

dToF直方图之美_deadtime死区时间

IMX459的死区时间可以在6ns,这个时间是什么级别,车载激光雷达激光器的光脉宽一般都在4ns以上,也就是这个时间贴近去SPAD的死区时间,这就导致了pile up会非常弱,不会有太多数量的光子计数堆积,加上某些SPAD设计,对TDC有一些更深入的考量,所以不需要去校正pile up算法。Sensor层面决定了pile up的复杂程度,如果一个dToF的SPAD一致性非常好,那么pile up校正可以简单到极致,也就是一句代码的事,比如IMX611,优秀到不需要后端去考虑校正pile up。

致力于lidar应用开发 2149

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【操作系统】生产者消费者问题分析(线程同步)

生产者消费者问题分析

Cout_Sev 2608

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【Java】进程同步问题——生产者、消费者问题

进程同步问题——生产者、消费者问题在这里插入图片描述       生产者、消费者问题是操作系统中个著名的进程同步问题。一般是指: 有一群生产者进程在生产产品,并将此产品提供给消费者进程去消费。为使生产者进程和消费者进程能并发执行,在它们之间设置一个缓冲区, 生产者进程可将它所产的产品放入一个缓冲区中,消费者进程可从一个缓冲区取得一个产品消...

Veni的博客 3795

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

《操作系统》课程设计报告——用JAVA语言模仿“生产者—消费者问题”

引言 操作系统是计算机的核心总控软件,是计算机系统的指挥和管理中心,是计算机系统的灵魂。进程管理与文件系统是操作系统都是操作系统的五大重要功能之一。通过模拟操作系统的实现,加深学生对计算机操作系统内核工作原理的理解,进一步了解操作系统的实现方法,提高对操作系统内核的分析与扩展能力,提高程序设计能力。为了深入理解进程管理与文件系统的内部功能与实现,本课程设计将用JAVA语言模仿“生产者—消费者问题”,并设计一个加入自己设计功能的多用户文件系统。 任务要求 操作系统原理是计算机专业的核心课程。本课程设计的

无限迭代中...... 5858

Nachos操作系统实验三:使用信号量解决生产者/消费者同步问题

Nachos操作系统实验三:使用信号量解决生产者/消费者同步问题注意实验目的实验思路实验过程1,生产者设置2,消费者设置3,整体控制4.编译,查看结果。 注意 所有单独修改部分均在其后方注释add here 整体修改部分均在其上下注释add here 实验提供的makefile文件应该是支持在原代码上直接修改的,所以如果要移动代码到新的文件夹,请自行修改makefile文件。 实验目的 使用操作系统信号量机制,编写程序解决生产者/消费者同步问题。 包括: 1.理解Nachos的信号量是如何实现的 2.生产者

m0_46422419的博客 1106

操作系统实验:进程和线程同步和互斥(生产者消费者问题,睡觉的理发师问题)

参考教材中的生产者消费者算法,创建5个进程,其中两个进程为生产者进程,3个进程为消费者进程。一个生产者进程试图不断地在一个缓冲中写入大写字母,另一个生产者进程试图不断地在缓冲中写入小写字母。为了使得程序的输出易于看到结果,仿照的实例程序,分别在生产者和消费者进程的合适的位置加入一些随机睡眠时间。当理发师处理完所有顾客,而又没有新顾客来时,他又开始睡觉。例如一个消费者只消费小写字符,一个消费者只消费大写字母,而另一个消费者则无选择地消费任何产品。消费者要消费的产品没有时,消费者进程被阻塞。

CH3CH2CH4的博客 1028

操作系统实验(13)多线程执行中的互斥与同步、多消费者多生产者问题(更新)

4、多线程编程实现一群生产者和一群消费者的生产和消费过程,使他们之间符合如下逻辑:没有产品不能消费,没有空不能放入 #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<errno.h> #include<fcntl.h> #include<signal.h> #include<linux/sem.h

qq_43656233的博客 1048

操作系统实验(1)python 生产者消费者问题

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

DFS的博客 3517

在操作系统中,生产者-消费者问题是一个经典的进程同步问题,其核心目标是协调多个进程(或线程)对共享缓冲区的访问

| 对比项 | 单缓冲区 | 多缓冲区 | |--------|----------|-----------| | 缓冲区数量 | 1 | n > 1 | | 并发风险 | 无(操作天然互斥) | 有(共享指针需保护) | | 是否需要 mutex | 否 | 是 | | 同步机制是否足够 | 是(S₁/S₂ 控制状态) | 否(还需保护临界区) | > ✅ 所以:**单缓冲区靠同步信号量即可实现逻辑互斥;多缓冲区必须显式使用互斥信号量来保护共享数据结构。**

[Blog][Domain] programb.blog.youkuaiyun.com 2589

操作系统-进程与线程(同步互斥典型模型-生产者,消费者模型、吸烟者问题)

王道计算机操作系统(线程同步互斥实例,生产者消费者模型,吸烟者模型)学习笔记心得。

dodamce的博客 969

操作系统: 生产者-消费者问题

操作系统: 生产者-消费者问题 1、单生产者和单消费者 缓存绑定问题,两个进程:生产者和消费者,一个固定大小的缓存。 生产者的工作就是制造一段数据,放进缓存,如此反复; 消费者则一次消费一段数据(将其从缓存中移除), 问题的核心: 就是要保证不让生产者在缓存还是满的时候仍要向缓存写数据, 不...

~ 577
上一篇: 为什么四次握手之后需要等待2MSL
下一篇: 操作系统线程同步之哲学家进餐问题
马冬冬
博客等级 码龄15年 54粉丝 519原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值