当前位置: 首页 > news >正文

C++笔记之不同buffer数量下的生产者-消费者机制

C++笔记之不同buffer数量下的生产者-消费者机制

文章目录

  • C++笔记之不同buffer数量下的生产者-消费者机制
    • 0.在不同的缓冲区数量下,生产者-消费者机制的实现方式和行为的区别
    • 1.最简单的生产者-消费者实现:抄自 https://mp.weixin.qq.com/s/G1lHNcbYU1lUlfugXnNhZg
    • 2.1个生产者,1个消费者,操作1个buffer,使用环形队列
    • 3.3个生产者,3个消费者,操作1个buffer
    • 4.3个生产者,3个消费者,操作2个buffer,双buffer中存在生产者和消费者交替操作同一个buffer逻辑
    • 5.1个生产者,1个消费者,操作3个buffer
    • 6.n个生产者,n个消费者,操作n个buffer
    • 7.在生产者-消费者中使用信号量

0.在不同的缓冲区数量下,生产者-消费者机制的实现方式和行为的区别

  1. 单个缓冲区:

    • 在单个缓冲区的情况下,生产者和消费者共享一个有限大小的缓冲区,生产者将数据放入缓冲区,而消费者从中取出数据。
    • 如果缓冲区已满,生产者必须等待,直到有空间可用。如果缓冲区为空,消费者必须等待,直到有数据可用。
    • 这种情况下,通常需要使用互斥锁来保护共享缓冲区,以确保多个线程或进程不会同时访问缓冲区,从而避免竞态条件。
  2. 多个缓冲区:

    • 在多个缓冲区的情况下,通常有多个生产者和多个消费者,每个生产者-消费者对共享一个缓冲区。这些缓冲区可以是独立的,也可以按照某种策略连接在一起。
    • 这种情况下,不同的生产者可以同时往不同的缓冲区放置数据,不同的消费者可以同时从不同的缓冲区取出数据,从而提高了并发性能。
    • 但是,管理多个缓冲区可能需要更复杂的同步和管理机制,以确保生产者和消费者之间的正确协作。

总的来说,单个缓冲区和多个缓冲区的主要区别在于资源的共享方式和并发性能。单个缓冲区通常更简单,但并发性能可能较低,因为所有的生产者和消费者都要竞争同一个缓冲区。多个缓冲区可以提高并发性能,但需要更复杂的管理和同步机制来维护多个缓冲区的状态。选择哪种方式取决于具体的应用需求和性能要求。

下面将比较这三种情况:一个缓冲区、两个缓冲区和三个缓冲区下的生产者-消费者机制的实现。

  1. 一个缓冲区:

    • 在这种情况下,你只需要一个共享的缓冲区,可以使用一个队列(如std::queue)来表示。
    • 生产者将数据放入队列的尾部,消费者从队列的头部取出数据。
    • 你需要使用互斥锁来保护队列,以确保生产者和消费者不会同时访问它。
    • 生产者在队列满时会阻塞,消费者在队列为空时会阻塞,可以使用条件变量来实现这种等待。
  2. 两个缓冲区:

    • 在这种情况下,你可以使用两个独立的缓冲区,每个缓冲区都有自己的队列。
    • 生产者可以交替将数据放入不同的队列,消费者也可以交替从不同的队列取出数据。
    • 这种方式可以提高并发性能,因为生产者和消费者可以并行操作不同的缓冲区。
    • 你需要使用互斥锁和条件变量来保护每个队列。
  3. 三个缓冲区:

    • 在这种情况下,你可以类似地使用三个独立的缓冲区,每个缓冲区有自己的队列。
    • 生产者和消费者之间的协作方式和两个缓冲区的情况类似,只是有更多的缓冲区可供使用。
    • 这可以进一步提高并发性能,但需要更复杂的管理和同步机制。

1.最简单的生产者-消费者实现:抄自 https://mp.weixin.qq.com/s/G1lHNcbYU1lUlfugXnNhZg

在 C++ 中可以使用 std::condition_variable 来实现生产者和消费者模式:生产者在缓冲区未满时不断添加数据,并唤醒消费者进行数据读取;消费者在缓存区为空时阻塞等待生产者的唤醒,并在读取数据后唤醒等待的生产者可以继续添加数据。
在这里插入图片描述

在这里插入图片描述

运行
在这里插入图片描述

代码


#include "condition_variable"
#include "iostream"
#include "queue"
#include "thread"
#include <mutex>using namespace std;class ProducerAndConsumerDemo {public:void producerNumber(); // 生产数据void consumerNumber(); // 消费数据private:const int dataSize = 1000;         // 总数据量queue<int> buffer;                 // 数据缓存区const int bufferSize = 10;         // 缓存区大小condition_variable bufferNotEmpty; // 信号量--缓存区有数据了condition_variable bufferNotFull;  // 信号量--缓存区不满了mutex m_mutex;                     // 互斥量
};void ProducerAndConsumerDemo::producerNumber() {for (int i = 0; i < dataSize; ++i) {{unique_lock<mutex> locker(m_mutex);bufferNotFull.wait(locker, [&]() { return buffer.size() < bufferSize; }); // 缓存区满了则阻塞buffer.push(i);cout << "生产者---生产了数字:" << i << ",当前 bufferSize:" << buffer.size() << endl;} // 解锁互斥量bufferNotEmpty.notify_one();this_thread::sleep_for(chrono::milliseconds(1000)); // 模拟生产耗时}
}void ProducerAndConsumerDemo::consumerNumber() {while (true) {{unique_lock<mutex> locker(m_mutex);bufferNotEmpty.wait(locker, [&]() { return buffer.size() > 0; }); // 缓冲区为空则阻塞int i = buffer.front();buffer.pop();cout << "消费者---消费了数字:" << i << ",当前 bufferSize:" << buffer.size() << endl;} // 解锁互斥量bufferNotFull.notify_one();this_thread::sleep_for(chrono::milliseconds(2000)); // 模拟消费耗时}
}int main() {ProducerAndConsumerDemo pcDemo;thread consumerThread(&ProducerAndConsumerDemo::producerNumber, &pcDemo);thread producerThread(&ProducerAndConsumerDemo::consumerNumber, &pcDemo);producerThread.join();consumerThread.join();system("pause");return 0;
}

2.1个生产者,1个消费者,操作1个buffer,使用环形队列

在这里插入图片描述

运行

在这里插入图片描述

代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>const int bufferSize = 5; // 缓冲区大小class CircularQueue {public:CircularQueue() : buffer(bufferSize), front(0), rear(0), count(0) {}// 生产者线程使用的enqueue函数,将数据添加到队列void enqueue(int item) {std::unique_lock<std::mutex> lock(mutex);// 检查队列是否已满if (count < bufferSize) {buffer[rear] = item;rear = (rear + 1) % bufferSize;count++;std::cout << "Produced: " << item << std::endl;// 通知等待中的消费者线程有新数据可用cv.notify_all();}}// 消费者线程使用的dequeue函数,从队列中取出数据int dequeue() {std::unique_lock<std::mutex> lock(mutex);// 如果队列为空,等待生产者生产数据while (count == 0) {cv.wait(lock);}// 从队列中取出数据int item = buffer[front];front = (front + 1) % bufferSize;count--;std::cout << "Consumed: " << item << std::endl;return item;}private:std::vector<int> buffer;    // 缓冲区,用于存储数据int front;                  // 队列前部索引int rear;                   // 队列后部索引int count;                  // 当前队列中的元素数量std::mutex mutex;           // 用于线程同步的互斥锁std::condition_variable cv; // 条件变量,用于线程等待和通知
};// 生产者线程函数,负责向队列中添加数据
void producer(CircularQueue &queue) {for (int i = 1; i <= 10; ++i) {queue.enqueue(i);// 模拟生产耗时std::this_thread::sleep_for(std::chrono::milliseconds(200));}
}// 消费者线程函数,负责从队列中取出数据
void consumer(CircularQueue &queue) {for (int i = 0; i < 10; ++i) {int item = queue.dequeue();// 模拟消费耗时std::this_thread::sleep_for(std::chrono::milliseconds(300));}
}int main() {CircularQueue queue;// 创建生产者线程和消费者线程std::thread producerThread(producer, std::ref(queue));std::thread consumerThread(consumer, std::ref(queue));// 等待线程结束producerThread.join();consumerThread.join();return 0;
}

3.3个生产者,3个消费者,操作1个buffer

这个示例中,有3个生产者线程和3个消费者线程,它们并行地生产和消费元素,使用互斥锁保护共享的队列,并使用条件变量来通知生产者和消费者缓冲区的状态。生产者线程生成随机整数并将其放入缓冲区,而消费者线程从缓冲区中取出元素并将其打印出来。每个生产者和消费者线程各执行5次操作。

在这里插入图片描述

运行

在这里插入图片描述

代码

#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>const int buffer_size = 3; // 缓冲区大小std::queue<int> buffer; // 环形队列
std::mutex mtx; // 互斥锁,用于保护缓冲区的访问
std::condition_variable not_full; // 条件变量,表示缓冲区不满
std::condition_variable not_empty; // 条件变量,表示缓冲区不空void producer(int id) {for (int i = 0; i < 5; ++i) {std::unique_lock<std::mutex> lock(mtx);while (buffer.size() >= buffer_size) {not_full.wait(lock); // 如果缓冲区已满,等待直到不满}int item = rand() % 100;buffer.push(item);std::cout << "Producer " << id << " produced: " << item << std::endl;not_empty.notify_all(); // 通知消费者缓冲区不空lock.unlock();std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟生产过程}
}void consumer(int id) {for (int i = 0; i < 5; ++i) {std::unique_lock<std::mutex> lock(mtx);while (buffer.empty()) {not_empty.wait(lock); // 如果缓冲区为空,等待直到不空}int item = buffer.front();buffer.pop();std::cout << "Consumer " << id << " consumed: " << item << std::endl;not_full.notify_all(); // 通知生产者缓冲区不满lock.unlock();std::this_thread::sleep_for(std::chrono::milliseconds(200)); // 模拟消费过程}
}int main() {std::vector<std::thread> producers;std::vector<std::thread> consumers;for (int i = 0; i < 3; ++i) {producers.emplace_back(producer, i);consumers.emplace_back(consumer, i);}for (auto& producer_thread : producers) {producer_thread.join();}for (auto& consumer_thread : consumers) {consumer_thread.join();}return 0;
}

4.3个生产者,3个消费者,操作2个buffer,双buffer中存在生产者和消费者交替操作同一个buffer逻辑

在这里插入图片描述
运行
在这里插入图片描述
代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>const int BUFFER_SIZE = 5; // 缓冲区大小std::mutex mtx;                                   // 互斥锁,用于保护共享资源
std::condition_variable producer_cv, consumer_cv; // 条件变量,用于线程同步
std::vector<int> buffer1, buffer2;                // 两个缓冲区,用于生产者和消费者之间的数据交换
int current_buffer = 1;                           // 标志,表示当前使用哪个缓冲区// 生产者函数
void producer() {for (int i = 0; i < 10; ++i) {std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟生产时间std::unique_lock<std::mutex> lock(mtx); // 获取互斥锁,保护共享资源if ((current_buffer == 1 && buffer1.size() >= BUFFER_SIZE) ||(current_buffer == 2 && buffer2.size() >= BUFFER_SIZE)) {// 缓冲区已满,生产者等待std::cout << "Buffer " << current_buffer << " 已满,生产者等待...\n";producer_cv.wait(lock, [] { return (current_buffer == 1 && buffer1.size() < BUFFER_SIZE) ||(current_buffer == 2 && buffer2.size() < BUFFER_SIZE); });}int item = i;if (current_buffer == 1) {buffer1.push_back(item);std::cout << "生产到缓冲区 1: " << item << std::endl;} else {buffer2.push_back(item);std::cout << "生产到缓冲区 2: " << item << std::endl;}lock.unlock();            // 释放互斥锁consumer_cv.notify_one(); // 通知一个等待的消费者线程// 切换使用的缓冲区current_buffer = (current_buffer == 1) ? 2 : 1;}
}// 消费者函数
void consumer() {for (int i = 0; i < 10; ++i) {std::this_thread::sleep_for(std::chrono::milliseconds(200)); // 模拟消费时间std::unique_lock<std::mutex> lock(mtx); // 获取互斥锁,保护共享资源if ((current_buffer == 1 && buffer1.empty()) ||(current_buffer == 2 && buffer2.empty())) {// 缓冲区为空,消费者等待std::cout << "消费者在用Buffer " << current_buffer << ",Buffer " << current_buffer << " 为空,消费者等待...\n";consumer_cv.wait(lock, [] { return (current_buffer == 1 && !buffer1.empty()) ||(current_buffer == 2 && !buffer2.empty()); });}int item;if (current_buffer == 1) {item = buffer1.front();buffer1.erase(buffer1.begin());std::cout << "从缓冲区 1 消费: " << item << std::endl;} else {item = buffer2.front();buffer2.erase(buffer2.begin());std::cout << "从缓冲区 2 消费: " << item << std::endl;}lock.unlock();            // 释放互斥锁producer_cv.notify_one(); // 通知一个等待的生产者线程// 切换使用的缓冲区current_buffer = (current_buffer == 1) ? 2 : 1;}
}int main() {std::thread producer_thread(producer); // 创建生产者线程std::thread consumer_thread(consumer); // 创建消费者线程producer_thread.join(); // 等待生产者线程结束consumer_thread.join(); // 等待消费者线程结束return 0;
}

5.1个生产者,1个消费者,操作3个buffer

在这里插入图片描述

运行
在这里插入图片描述

代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>const int BUFFER_COUNT = 3;std::mutex mtx;
std::condition_variable cv_producer, cv_consumer;std::vector<std::queue<int>> buffers(BUFFER_COUNT);int current_buffer = 0;void producer() {for (int i = 1; i <= 10; ++i) {std::unique_lock<std::mutex> lock(mtx);// 检查当前缓冲区是否已满while (!buffers[current_buffer].empty()) {cv_producer.wait(lock);}buffers[current_buffer].push(i);std::cout << "生产者生产了: " << i << " 到缓冲区: " << current_buffer << std::endl;current_buffer = (current_buffer + 1) % BUFFER_COUNT;// 唤醒消费者cv_consumer.notify_all();}
}void consumer() {for (int i = 1; i <= 10; ++i) {std::unique_lock<std::mutex> lock(mtx);// 检查当前缓冲区是否为空while (buffers[current_buffer].empty()) {cv_consumer.wait(lock);}int item = buffers[current_buffer].front();buffers[current_buffer].pop();std::cout << "消费者消费了: " << item << " 从缓冲区: " << current_buffer << std::endl;current_buffer = (current_buffer + 1) % BUFFER_COUNT;// 唤醒生产者cv_producer.notify_all();}
}int main() {std::thread producer_thread(producer);std::thread consumer_thread(consumer);producer_thread.join();consumer_thread.join();return 0;
}

6.n个生产者,n个消费者,操作n个buffer

在这里插入图片描述

运行:偶尔会core dump
在这里插入图片描述

代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>const int num_buffers = 3;                 // 缓冲区的数量
const int buffer_size = 5;                 // 每个缓冲区的大小
const int producers_and_consumers_num = 3; // 生产者和消费者的数量std::vector<int> buffers[num_buffers];          // 多个缓冲区,每个缓冲区是一个整数向量
std::mutex buffer_mutexes[num_buffers];         // 与每个缓冲区相关联的互斥锁
std::condition_variable buffer_cv[num_buffers]; // 与每个缓冲区相关联的条件变量// 生产者线程函数
void producer(int id) {for (int i = 0; i < 10; ++i) {// 查找具有最多可用空间的缓冲区int max_space = -1;int selected_buffer = -1;for (int j = 0; j < num_buffers; ++j) {std::unique_lock<std::mutex> lock(buffer_mutexes[j]);int space = buffer_size - buffers[j].size();if (space > max_space) {max_space = space;selected_buffer = j;}}// 等待直到有足够的空间可以生产while (buffers[selected_buffer].size() >= buffer_size) {std::unique_lock<std::mutex> lock(buffer_mutexes[selected_buffer]);buffer_cv[selected_buffer].wait(lock);}// 生产数据并将其放入缓冲区buffers[selected_buffer].push_back(id * 100 + i);std::cout << "生产者 " << id << " 生产了 " << id * 100 + i << " 放入缓冲区 " << selected_buffer << std::endl;// 通知等待的消费者线程buffer_cv[selected_buffer].notify_one();}
}// 消费者线程函数
void consumer(int id) {for (int i = 0; i < 10; ++i) {// 查找具有最少可用空间的缓冲区,这表示有数据等待消费int min_space = buffer_size + 1;int selected_buffer = -1;for (int j = 0; j < num_buffers; ++j) {std::unique_lock<std::mutex> lock(buffer_mutexes[j]);int space = buffer_size - buffers[j].size();if (space < min_space) {min_space = space;selected_buffer = j;}}// 等待直到有数据可以消费while (buffers[selected_buffer].empty()) {std::unique_lock<std::mutex> lock(buffer_mutexes[selected_buffer]);buffer_cv[selected_buffer].wait(lock);}// 检查缓冲区是否为空,然后再消费数据if (!buffers[selected_buffer].empty()) {int data = buffers[selected_buffer].back();buffers[selected_buffer].pop_back();std::cout << "消费者 " << id << " 消费了 " << data << " 从缓冲区 " << selected_buffer << std::endl;}// 通知等待的生产者线程buffer_cv[selected_buffer].notify_one();}
}int main() {std::thread producers[producers_and_consumers_num];std::thread consumers[producers_and_consumers_num];// 创建生产者和消费者线程for (int i = 0; i < producers_and_consumers_num; ++i) {producers[i] = std::thread(producer, i);consumers[i] = std::thread(consumer, i);}// 等待所有线程完成for (int i = 0; i < producers_and_consumers_num; ++i) {producers[i].join();consumers[i].join();}return 0;
}

7.在生产者-消费者中使用信号量

这个示例模拟了一个生产者-消费者问题,其中多个生产者线程和消费者线程共享一个有界缓冲区,信号量用于控制对缓冲区的并发访问。

在此示例中,有三个生产者线程和三个消费者线程,它们共享一个有界缓冲区。Semaphore类用于控制缓冲区的空闲和满状态。生产者线程生成随机项目并将它们放入缓冲区,然后通知消费者线程。消费者线程从缓冲区中取出项目并通知生产者线程。信号量确保缓冲区在多线程环境中得到正确的访问和同步。

这个示例有助于理解信号量在多线程环境中的应用,尤其是在生产者-消费者问题中的作用。通过信号量,可以控制多个线程之间的并发访问,以避免数据竞态和确保正确的协调。

在这里插入图片描述

运行
在这里插入图片描述

代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>const int BUFFER_SIZE = 5;class Semaphore {public:Semaphore(int count = 0) : count_(count) {}void notify() {std::unique_lock<std::mutex> lock(mutex_);count_++;cv_.notify_one();}void wait() {std::unique_lock<std::mutex> lock(mutex_);while (count_ == 0) {cv_.wait(lock);}count_--;}private:std::mutex mutex_;std::condition_variable cv_;int count_;
};Semaphore empty(BUFFER_SIZE); // 空缓冲区的信号量
Semaphore full(0);            // 满缓冲区的信号量
std::mutex bufferMutex;       // 缓冲区互斥量
std::queue<int> buffer;       // 共享缓冲区void producer(int id) {for (int i = 0; i < 10; ++i) {int item = rand() % 100; // 随机生成一个项目empty.wait();            // 等待空缓冲区bufferMutex.lock();      // 锁定缓冲区buffer.push(item);       // 将项目放入缓冲区std::cout << "Producer " << id << " produced: " << item << std::endl;bufferMutex.unlock(); // 解锁缓冲区full.notify();        // 通知缓冲区已满std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}void consumer(int id) {for (int i = 0; i < 10; ++i) {full.wait();        // 等待满缓冲区bufferMutex.lock(); // 锁定缓冲区int item = buffer.front();buffer.pop();std::cout << "Consumer " << id << " consumed: " << item << std::endl;bufferMutex.unlock(); // 解锁缓冲区empty.notify();       // 通知缓冲区已空std::this_thread::sleep_for(std::chrono::milliseconds(250));}
}int main() {std::vector<std::thread> producers;std::vector<std::thread> consumers;for (int i = 0; i < 3; ++i) {producers.emplace_back(producer, i);consumers.emplace_back(consumer, i);}for (auto &producerThread : producers) {producerThread.join();}for (auto &consumerThread : consumers) {consumerThread.join();}return 0;
}

相关文章:

C++笔记之不同buffer数量下的生产者-消费者机制

C笔记之不同buffer数量下的生产者-消费者机制 文章目录 C笔记之不同buffer数量下的生产者-消费者机制0.在不同的缓冲区数量下&#xff0c;生产者-消费者机制的实现方式和行为的区别1.最简单的生产者-消费者实现&#xff1a;抄自 https://mp.weixin.qq.com/s/G1lHNcbYU1lUlfugXn…...

编码文字使用整数xyz 三个坐标 并使用

导航 说明原始描述AI理解的实现代码说明 原始描述 而后期的,相同的s,前缀差距 和 自身权重 要对应的上,或者说 假设每个序列都是三维空间上的点集合,使用最小的空间表达这些信息,整个数据集才是重点。这些点的集合可以 是空间直线或者是曲线 整体的思路是 一个集合能在任…...

创建vue3工程

一、新建工程目录E:\vue\projectCode\npm-demo用Visual Studio Code 打开目录 二、点击新建文件夹按钮&#xff0c;新建vue3-01-core文件夹 三、右键vue3-01-core文件夹点击在集成终端中打开 四、初始化项目&#xff0c;输入npm init 一直敲回车直到创建成功如下图 npm init 五…...

Flutter笔记 - 用于描述Align的Alignment、AlignmentDirectional、AlignmentTween类

Flutter笔记 用于描述Align的Alignment、AlignmentDirectional、AlignmentTween类 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_…...

门面模式简介

门面模式简介 门面模式&#xff08;Facade Pattern&#xff09;是一种结构性设计模式&#xff0c;它提供了一个简化复杂系统的接口&#xff0c;允许客户端通过一个统一的接口与系统交互&#xff0c;而不需要了解系统内部的复杂性。这个模式的目标是降低客户端与系统之间的耦合…...

2023年7月工作经历二

invoke的翻译 C#的这个关键字很熟&#xff0c;但不知道如何翻译比较好。和网友沟通&#xff0c;并查阅多篇博文&#xff0c;觉得“同步调用&#xff08;invoke&#xff09;和异步调用(beginvoke)”比较好。 VS2022很爽 C#的类名&#xff0c;会提示命名空间。C调试的时候&…...

7.wifi开发【智能家居:终】,实践总结:智能开关,智能采集温湿,智能灯。项目运行步骤与运行细节,技术归纳与提炼,项目扩展

一。项目运行步骤与运行细节 1.项目运行步骤&#xff08;一定有其他的运行方式&#xff0c;我这里只提供一种我现在使用的编译方式&#xff09; &#xff08;1&#xff09;项目运行使用软件与技术&#xff1a; 1.Virtual linux 使用这个虚拟机进行程序的编译 2.Makefile与shl…...

学习开发一个RISC-V上的操作系统(汪辰老师) — unrecognized opcode `csrr t0,mhartid‘报错问题

前言 &#xff08;1&#xff09;此系列文章是跟着汪辰老师的RISC-V课程所记录的学习笔记。 &#xff08;2&#xff09;该课程相关代码gitee链接&#xff1b; &#xff08;3&#xff09;PLCT实验室实习生长期招聘&#xff1a;招聘信息链接 正文 &#xff08;1&#xff09;在跟着…...

【计算机网络】 心跳机制

文章目录 心跳机制应用场景什么是心跳机制心跳包的发送&#xff0c;通常有两种技术 心跳机制 应用场景 在长连接下&#xff0c;有可能很长一段时间没有数据往来。理论上说&#xff0c;这个连接是一直保持连接的&#xff0c;但是实际情况中&#xff0c;如果中间节点出现什么故…...

文心一言 VS 讯飞星火 VS chatgpt (106)-- 算法导论10.1 4题

四、用go语言&#xff0c;重写 ENQUEUE 和 DEQUEUE 的代码&#xff0c;使之能处理队列的下溢和上溢。 文心一言&#xff1a; 在 Go 语言中&#xff0c;我们可以使用切片来实现队列。下面是如何实现 ENQUEUE 和 DEQUEUE 操作&#xff0c;同时处理队列的下溢和上溢的情况&#…...

进程调度算法之时间片轮转调度(RR),优先级调度以及多级反馈队列调度

1.时间片轮转调度算法(RR) round Robin 1.算法思想 公平地、轮流地为各个进程服务&#xff0c;让每个进程在一定时间间隔内都可以得到响应。 2.算法规则 按照各进程到达就绪队列的顺序&#xff0c;轮流让各个进程执行一个时间片&#xff08;如100ms&#xff09;。 若进程未…...

ARMv8如何读取cache line中MESI 状态以及Tag信息(tag RAM dirty RAM)并以Cortex-A55示例

Cortex-A55 MESI 状态获取 一&#xff0c;系统寄存器以及读写指令二&#xff0c;Cortex-A55 Data cache的MESI信息获取&#xff08;AARCH 64&#xff09;2.1 将Set/way信息写入Data Cache Tag Read Operation Register2.2 读取Data Register 1和Data Register 0数据并解码 参考…...

密码技术 (6) - 证书

一. 前言 前面介绍的公钥密码和数字签名&#xff0c;都无法解决一个问题&#xff0c;那就是判断自己获取的公钥是否期望的&#xff0c;不能确定公钥是否被中间攻击人掉包。所以&#xff0c;证书的作用是用来证明公钥是否合法的。本文介绍的证书就是解决证书的可靠性的技术。 二…...

【算法学习】-【双指针】-【盛水最多的容器】

LeetCode原题链接&#xff1a;盛水最多的容器 下面是题目描述&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。…...

JAVA面经整理(8)

一)为什么要有区&#xff0c;段&#xff0c;页&#xff1f; 1)页是内存和磁盘之间交互的基本单位内存中的值修改之后刷到磁盘的时候还是以页为单位的索引结构给程序员提供了高效的索引实现方式&#xff0c;不过索引信息以及数据记录都是记录在文件上面的&#xff0c;确切来说是…...

【Java 进阶篇】JDBC数据库连接池Druid详解

在Java应用程序中&#xff0c;与数据库进行交互是一个常见的任务。为了更有效地管理数据库连接并提高性能&#xff0c;数据库连接池是一种常见的解决方案。Druid是一个流行的JDBC数据库连接池&#xff0c;它具有丰富的功能和高性能。本博客将详细介绍Druid连接池&#xff0c;包…...

Linux——指令初识

Linux下基本指令 前言一、 ls 指令二、 pwd命令三、cd 指令四、 touch指令五、mkdir指令六、rmdir指令 && rm 指令七、man指令八、cp指令九、mv指令十、cat指令十一、.more指令十二、less指令十三、head指令十四、tail指令总结 前言 linux的学习开始啦&#xff01; 今…...

专题一:双指针【优选算法】

双指针应用场景&#xff1a; 数组划分、数组分块 目录 一、移动0 二、复写0 从后向前 三、快乐数 链表带环 四、盛水最多的容器 单调性双指针 五、有效三角形个数 单调性双指针 六、和为s的两个数字 七、三数之和 细节多 需再练 一、移动0 class Solution { public:void move…...

蓝桥等考Python组别十二级007

第一部分:选择题 1、Python L12 (15分) 运行下面程序,输出的结果是( )。 lis = [A, B, C, D, E, F] print(lis[0 : 3]) [A, B, C][A, B][A, B, C, D][B, C, D]正确答案:A 2...

全方位介绍工厂的MES质量检验管理系统

一、MES质量检验管理系统的定义&#xff1a; MES质量检验管理系统是基于制造执行系统的框架和功能&#xff0c;专注于产品质量的控制和管理。它通过整合和优化质量检验流程&#xff0c;提供实时的数据采集、分析和反馈&#xff0c;帮助工厂实现高效的质量管理。该系统涵盖了从…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

NineData数据库DevOps功能全面支持百度智能云向量数据库 VectorDB,助力企业 AI 应用高效落地

NineData 的数据库 DevOps 解决方案已完成对百度智能云向量数据库 VectorDB 的全链路适配&#xff0c;成为国内首批提供 VectorDB 原生操作能力的服务商。此次合作聚焦 AI 开发核心场景&#xff0c;通过标准化 SQL 工作台与细粒度权限管控两大能力&#xff0c;助力企业安全高效…...

JavaScript性能优化实战大纲

性能优化的核心目标 降低页面加载时间&#xff0c;减少内存占用&#xff0c;提高代码执行效率&#xff0c;确保流畅的用户体验。 代码层面的优化 减少全局变量使用&#xff0c;避免内存泄漏 // 不好的实践 var globalVar I am global;// 好的实践 (function() {var localV…...

【VLAs篇】02:Impromptu VLA—用于驱动视觉-语言-动作模型的开放权重和开放数据

项目描述论文标题Impromptu VLA&#xff1a;用于驱动视觉-语言-动作模型的开放权重和开放数据 (Impromptu VLA: Open Weights and Open Data for Driving Vision-Language-Action Models)研究问题自动驾驶的视觉-语言-动作 (VLA) 模型在非结构化角落案例场景中表现不佳&#xf…...

学习英语。

1. 先自己翻译一遍&#xff08;葫芦背书法&#xff09; 结构 补充修饰 最核心的记忆 然后再修饰 2.意群之间翻译&#xff1a; 1.意群 对于两个意群合起来翻译 方法1就是着重某一 6.或者意群之间 核心词一个介词 于 对于 介词化修饰 3.句子之间关系 主句1 after句子2 那么句…...