C++实现生产者和消费者模型

2023-10-26

C++实现生产者和消费者模型

1、实现细节

  • 具体的实现逻辑是构建一个queue来存储生产的数据,queue不满时可以生产,不空时可以消费。
  • 对于这个队列,采用阻塞队列的实现思路。
  • 先实现构造函数,初始化一个unique_lock供condition_variable使用。
    • 如何在类里面使用unique_lock等需要初始化,并且初始化会加锁的对象。这要研究下。我的理解是构造列表初始化,然后函数体里unlock。
    • 对于条件变量,申请两个,分别控制consumer和producer。
  • 然后就是入和出队列的细节。
    • 首先加锁。
    • 循环判断一下目前的队列情况,对于各自的特殊情况(队满和队空)进行处理。
    • 唤醒一个线程来处理特殊情况。
    • 等待处理完毕。
    • 处理入和出队列操作。
    • 最后释放锁。

2、单生产者-单消费者模型

  • 单生产者-单消费者模型中只有一个生产者和一个消费者,
  • 生产者不停地往产品库中放入产品,
  • 消费者则从产品库中取走产品,
  • 产品库容积有限制,只能容纳一定数目的产品,
  • 如果生产者生产产品的速度过快,则需要等待消费者取走产品之后,产品库不为空才能继续往产品库中放置新的产品,
  • 相反,如果消费者取走产品的速度过快,则可能面临产品库中没有产品可使用的情况,此时需要等待生产者放入一个产品后,消费者才能继续工作。

C++11实现单生产者单消费者模型的代码如下:

#include <unistd.h>

#include <cstdlib>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

static const int bufSize = 10; // Item buffer size.
static const int ProNum = 20;   // How many items we plan to produce.

struct resource {
	int buf[bufSize]; // 产品缓冲区, 配合 read_pos 和 write_pos 模型环形队列.
	size_t read_pos; // 消费者读取产品位置.
	size_t write_pos; // 生产者写入产品位置.
	std::mutex mtx; // 互斥量,保护产品缓冲区
	std::condition_variable not_full; // 条件变量, 指示产品缓冲区不为满.
	std::condition_variable not_empty; // 条件变量, 指示产品缓冲区不为空.
} instance; // 产品库全局变量, 生产者和消费者操作该变量.

typedef struct resource resource;


void Producer(resource *ir, int item)
{
	std::unique_lock<std::mutex> lock(ir->mtx);
	while (((ir->write_pos + 1) % bufSize)
		== ir->read_pos) { // item buffer is full, just wait here.
		std::cout << "Producer is waiting for an empty slot...\n";
		(ir->not_full).wait(lock); // 生产者等待"产品库缓冲区不为满"这一条件发生.
	}

	(ir->buf)[ir->write_pos] = item; // 写入产品.
	(ir->write_pos)++; // 写入位置后移.

	if (ir->write_pos == bufSize) // 写入位置若是在队列最后则重新设置为初始位置.
		ir->write_pos = 0;

	(ir->not_empty).notify_all(); // 通知消费者产品库不为空.
}

int Consumer(resource *ir)
{
	int data;
	std::unique_lock<std::mutex> lock(ir->mtx);
	// item buffer is empty, just wait here.
	while (ir->write_pos == ir->read_pos) {
		std::cout << "Consumer is waiting for items...\n";
		(ir->not_empty).wait(lock); // 消费者等待"产品库缓冲区不为空"这一条件发生.
	}

	data = (ir->buf)[ir->read_pos]; // 读取某一产品
	(ir->read_pos)++; // 读取位置后移

	if (ir->read_pos >= bufSize) // 读取位置若移到最后,则重新置位.
		ir->read_pos = 0;

	(ir->not_full).notify_all(); // 通知消费者产品库不为满.

	return data; // 返回产品.
}


void ProducerTask() // 生产者任务
{
	for (int i = 1; i <= ProNum; ++i) {
		// sleep(1);
		std::cout << "Produce the " << i << "^th item..." << std::endl;
		Producer(&instance, i); // 循环生产 ProNum 个产品.
	}
}

void ConsumerTask() // 消费者任务
{
	static int cnt = 0;
	while (1) {
		sleep(1);
		int item = Consumer(&instance); // 消费一个产品.
		std::cout << "Consume the " << item << "^th item" << std::endl;
		if (++cnt == ProNum) break; // 如果产品消费个数为 ProNum, 则退出.
	}
}

void Initresource(resource *ir)
{
	ir->write_pos = 0; // 初始化产品写入位置.
	ir->read_pos = 0; // 初始化产品读取位置.
}

int main()
{
	Initresource(&instance);
	std::thread producer(ProducerTask); // 创建生产者线程.
	std::thread consumer(ConsumerTask); // 创建消费之线程.
	producer.join();
	consumer.join();
}

在这里插入图片描述

3、单生产者-多消费者模型

与单生产者和单消费者模型不同的是,单生产者-多消费者模型中可以允许多个消费者同时从产品库中取走产品。所以除了保护产品库在多个读写线程下互斥之外,还需要维护消费者取走产品的计数器,代码如下:

#include <unistd.h>

#include <cstdlib>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

static const int bufSize = 8; // Item buffer size.
static const int ProNum = 30;   // How many items we plan to produce.

struct resource {
	int buf[bufSize]; // 产品缓冲区, 配合 read_pos 和 write_pos 模型环形队列.
	size_t read_pos; // 消费者读取产品位置.
	size_t write_pos; // 生产者写入产品位置.
	size_t item_counter;
	std::mutex mtx; // 互斥量,保护产品缓冲区
	std::mutex item_counter_mtx;
	std::condition_variable not_full; // 条件变量, 指示产品缓冲区不为满.
	std::condition_variable not_empty; // 条件变量, 指示产品缓冲区不为空.
} instance; // 产品库全局变量, 生产者和消费者操作该变量.

typedef struct resource resource;


void Producer(resource *ir, int item)
{
	std::unique_lock<std::mutex> lock(ir->mtx);
	while (((ir->write_pos + 1) % bufSize)
		== ir->read_pos) { // item buffer is full, just wait here.
		std::cout << "Producer is waiting for an empty slot...\n";
		(ir->not_full).wait(lock); // 生产者等待"产品库缓冲区不为满"这一条件发生.
	}

	(ir->buf)[ir->write_pos] = item; // 写入产品.
	(ir->write_pos)++; // 写入位置后移.

	if (ir->write_pos == bufSize) // 写入位置若是在队列最后则重新设置为初始位置.
		ir->write_pos = 0;

	(ir->not_empty).notify_all(); // 通知消费者产品库不为空.
	lock.unlock(); // 解锁.
}

int Consumer(resource *ir)
{
	int data;
	std::unique_lock<std::mutex> lock(ir->mtx);
	// item buffer is empty, just wait here.
	while (ir->write_pos == ir->read_pos) {
		std::cout << "Consumer is waiting for items...\n";
		(ir->not_empty).wait(lock); // 消费者等待"产品库缓冲区不为空"这一条件发生.
	}

	data = (ir->buf)[ir->read_pos]; // 读取某一产品
	(ir->read_pos)++; // 读取位置后移

	if (ir->read_pos >= bufSize) // 读取位置若移到最后,则重新置位.
		ir->read_pos = 0;

	(ir->not_full).notify_all(); // 通知消费者产品库不为满.
	lock.unlock(); // 解锁.

	return data; // 返回产品.
}


void ProducerTask() // 生产者任务
{
	for (int i = 1; i <= ProNum; ++i) {
		// sleep(1);
		std::cout << "Producer thread " << std::this_thread::get_id()
			<< " producing the " << i << "^th item..." << std::endl;
		Producer(&instance, i); // 循环生产 ProNum 个产品.
	}
	std::cout << "Producer thread " << std::this_thread::get_id()
		<< " is exiting..." << std::endl;
}

void ConsumerTask() // 消费者任务
{
	bool ready_to_exit = false;
	while (1) {
		sleep(1);
		std::unique_lock<std::mutex> lock(instance.item_counter_mtx);
		if (instance.item_counter < ProNum) {
			int item = Consumer(&instance);
			++(instance.item_counter);
			std::cout << "Consumer thread " << std::this_thread::get_id()
				<< " is consuming the " << item << "^th item" << std::endl;
		}
		else
			ready_to_exit = true;
		if (ready_to_exit == true)
			break;
	}
	std::cout << "Consumer thread " << std::this_thread::get_id()
		<< " is exiting..." << std::endl;
}

void Initresource(resource *ir)
{
	ir->write_pos = 0; // 初始化产品写入位置.
	ir->read_pos = 0; // 初始化产品读取位置.
	ir->item_counter = 0;
}

int main()
{
	Initresource(&instance);
	std::thread producer(ProducerTask);
	std::thread consumer1(ConsumerTask);
	std::thread consumer2(ConsumerTask);
	std::thread consumer3(ConsumerTask);
	std::thread consumer4(ConsumerTask);

	producer.join();
	consumer1.join();
	consumer2.join();
	consumer3.join();
	consumer4.join();
}

在这里插入图片描述

4、多生产者-单消费者模型

与单生产者和单消费者模型不同的是,多生产者-单消费者模型中可以允许多个生产者同时向产品库中放入产品。所以除了保护产品库在多个读写线程下互斥之外,还需要维护生产者放入产品的计数器,代码如下:

#include <unistd.h>

#include <cstdlib>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

static const int bufSize = 8; // Item buffer size.
static const int ProNum = 20;   // How many items we plan to produce.

struct resource {
	int buf[bufSize]; // 产品缓冲区, 配合 read_pos 和 write_pos 模型环形队列.
	size_t read_pos; // 消费者读取产品位置.
	size_t write_pos; // 生产者写入产品位置.
	size_t item_counter;
	std::mutex mtx; // 互斥量,保护产品缓冲区
	std::mutex item_counter_mtx;
	std::condition_variable not_full; // 条件变量, 指示产品缓冲区不为满.
	std::condition_variable not_empty; // 条件变量, 指示产品缓冲区不为空.
} instance; // 产品库全局变量, 生产者和消费者操作该变量.

typedef struct resource resource;


void Producer(resource *ir, int item)
{
	std::unique_lock<std::mutex> lock(ir->mtx);
	while (((ir->write_pos + 1) % bufSize)
		== ir->read_pos) { // item buffer is full, just wait here.
		std::cout << "Producer is waiting for an empty slot...\n";
		(ir->not_full).wait(lock); // 生产者等待"产品库缓冲区不为满"这一条件发生.
	}

	(ir->buf)[ir->write_pos] = item; // 写入产品.
	(ir->write_pos)++; // 写入位置后移.

	if (ir->write_pos == bufSize) // 写入位置若是在队列最后则重新设置为初始位置.
		ir->write_pos = 0;

	(ir->not_empty).notify_all(); // 通知消费者产品库不为空.
}

int Consumer(resource *ir)
{
	int data;
	std::unique_lock<std::mutex> lock(ir->mtx);
	// item buffer is empty, just wait here.
	while (ir->write_pos == ir->read_pos) {
		std::cout << "Consumer is waiting for items...\n";
		(ir->not_empty).wait(lock); // 消费者等待"产品库缓冲区不为空"这一条件发生.
	}

	data = (ir->buf)[ir->read_pos]; // 读取某一产品
	(ir->read_pos)++; // 读取位置后移

	if (ir->read_pos >= bufSize) // 读取位置若移到最后,则重新置位.
		ir->read_pos = 0;

	(ir->not_full).notify_all(); // 通知消费者产品库不为满.

	return data; // 返回产品.
}


void ProducerTask() // 生产者任务
{
	bool ready_to_exit = false;
	while (1) {
		sleep(1);
		std::unique_lock<std::mutex> lock(instance.item_counter_mtx);
		if (instance.item_counter < ProNum) {
			++(instance.item_counter);
			Producer(&instance, instance.item_counter);
			std::cout << "Producer thread " << std::this_thread::get_id()
				<< " is producing the " << instance.item_counter
				<< "^th item" << std::endl;
		}
		else 
			ready_to_exit = true;
		if (ready_to_exit == true) 
			break;
	}
	std::cout << "Producer thread " << std::this_thread::get_id()
		<< " is exiting..." << std::endl;
}

void ConsumerTask() // 消费者任务
{
	static int cnt = 0;
	while (1) {
		sleep(1);
		cnt++;
		if (cnt <= ProNum)
		{
			int item = Consumer(&instance); // 消费一个产品.
			std::cout << "Consumer thread " << std::this_thread::get_id()
				<< " is consuming the " << item << "^th item" << std::endl;
		}
		
		else
			break; // 如果产品消费个数为 ProNum, 则退出.
	}
	std::cout << "Consumer thread " << std::this_thread::get_id()
		<< " is exiting..." << std::endl;
}

void Initresource(resource *ir)
{
	ir->write_pos = 0; // 初始化产品写入位置.
	ir->read_pos = 0; // 初始化产品读取位置.
	ir->item_counter = 0;
}

int main()
{
	Initresource(&instance);
	std::thread producer1(ProducerTask);
	std::thread producer2(ProducerTask);
	std::thread producer3(ProducerTask);
	std::thread producer4(ProducerTask);
	std::thread consumer(ConsumerTask);

	producer1.join();
	producer2.join();
	producer3.join();
	producer4.join();
	consumer.join();
}

在这里插入图片描述

5、多生产者-多消费者模型

该模型可以说是前面两种模型的综合,程序需要维护两个计数器,分别是生产者已生产产品的数目和消费者已取走产品的数目。另外也需要保护产品库在多个生产者和多个消费者互斥地访问。

#include <unistd.h>

#include <cstdlib>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

static const int bufSize = 8; // Item buffer size.
static const int ProNum = 20;   // How many items we plan to produce.

struct resource {
	int buf[bufSize]; // 产品缓冲区, 配合 read_pos 和 write_pos 模型环形队列.
	size_t read_pos; // 消费者读取产品位置.
	size_t write_pos; // 生产者写入产品位置.
	size_t pro_item_counter;
	size_t con_item_counter;
	std::mutex mtx; // 互斥量,保护产品缓冲区
	std::mutex pro_mtx;
	std::mutex con_mtx;
	std::condition_variable not_full; // 条件变量, 指示产品缓冲区不为满.
	std::condition_variable not_empty; // 条件变量, 指示产品缓冲区不为空.
} instance; // 产品库全局变量, 生产者和消费者操作该变量.

typedef struct resource resource;


void Producer(resource *ir, int item)
{
	std::unique_lock<std::mutex> lock(ir->mtx);
	while (((ir->write_pos + 1) % bufSize)
		== ir->read_pos) { // item buffer is full, just wait here.
		std::cout << "Producer is waiting for an empty slot...\n";
		(ir->not_full).wait(lock); // 生产者等待"产品库缓冲区不为满"这一条件发生.
	}

	(ir->buf)[ir->write_pos] = item; // 写入产品.
	(ir->write_pos)++; // 写入位置后移.

	if (ir->write_pos == bufSize) // 写入位置若是在队列最后则重新设置为初始位置.
		ir->write_pos = 0;

	(ir->not_empty).notify_all(); // 通知消费者产品库不为空.
}

int Consumer(resource *ir)
{
	int data;
	std::unique_lock<std::mutex> lock(ir->mtx);
	// item buffer is empty, just wait here.
	while (ir->write_pos == ir->read_pos) {
		std::cout << "Consumer is waiting for items...\n";
		(ir->not_empty).wait(lock); // 消费者等待"产品库缓冲区不为空"这一条件发生.
	}

	data = (ir->buf)[ir->read_pos]; // 读取某一产品
	(ir->read_pos)++; // 读取位置后移

	if (ir->read_pos >= bufSize) // 读取位置若移到最后,则重新置位.
		ir->read_pos = 0;

	(ir->not_full).notify_all(); // 通知消费者产品库不为满.

	return data; // 返回产品.
}


void ProducerTask() // 生产者任务
{
	bool ready_to_exit = false;
	while (1) {
		sleep(1);
		std::unique_lock<std::mutex> lock(instance.pro_mtx);
		if (instance.pro_item_counter < ProNum) {
			++(instance.pro_item_counter);
			Producer(&instance, instance.pro_item_counter);
			std::cout << "Producer thread " << std::this_thread::get_id()
				<< " is producing the " << instance.pro_item_counter
				<< "^th item" << std::endl;
		}
		else 
			ready_to_exit = true;
		lock.unlock();
		if (ready_to_exit == true) 
			break;
	}
	std::cout << "Producer thread " << std::this_thread::get_id()
		<< " is exiting..." << std::endl;
}

void ConsumerTask() // 消费者任务
{
	bool ready_to_exit = false;
	while (1) {
		sleep(1);
		std::unique_lock<std::mutex> lock(instance.con_mtx);
		if (instance.con_item_counter < ProNum) {
			int item = Consumer(&instance);
			++(instance.con_item_counter);
			std::cout << "Consumer thread " << std::this_thread::get_id()
				<< " is consuming the " << item << "^th item" << std::endl;
		}
		else
			ready_to_exit = true;
		lock.unlock();
		if (ready_to_exit == true)
			break;
	}
	std::cout << "Consumer thread " << std::this_thread::get_id()
		<< " is exiting..." << std::endl;
}

void Initresource(resource *ir)
{
	ir->write_pos = 0; // 初始化产品写入位置.
	ir->read_pos = 0; // 初始化产品读取位置.
	ir->pro_item_counter = 0;
	ir->con_item_counter = 0;
}

int main()
{
	Initresource(&instance);
	std::thread producer1(ProducerTask);
	std::thread producer2(ProducerTask);
	std::thread producer3(ProducerTask);
	std::thread producer4(ProducerTask);

	std::thread consumer1(ConsumerTask);
	std::thread consumer2(ConsumerTask);
	std::thread consumer3(ConsumerTask);
	std::thread consumer4(ConsumerTask);

	producer1.join();
	producer2.join();
	producer3.join();
	producer4.join();

	consumer1.join();
	consumer2.join();
	consumer3.join();
	consumer4.join();
	return 0;
}

在这里插入图片描述

参考

1、https://www.cnblogs.com/haippy/p/3252092.html
2、https://blog.csdn.net/qq_41681241/article/details/86708303
3、https://blog.csdn.net/h_wulingfei/article/details/104897449

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++实现生产者和消费者模型 的相关文章

  • UTF8/UTF16 和 Base64 在编码方面有什么区别

    In c 我们可以使用下面的类来进行编码 System Text Encoding UTF8 System Text Encoding UTF16 System Text Encoding ASCII 为什么没有System Text En
  • 在 LINQ 查询中返回不带时间的日期

    我正在编写一个查询 我想计算按日期联系我们的呼叫中心的次数 看起来很简单 但由于联系日期字段是日期时间字段 我得到了时间 因此当我按联系日期 时间 分组时 每个联系日期实例的计数为 1 所以 我想只按日期分组 而不按时间分组 下面是我用来查
  • Signalr 在生产服务器中总是陷入长轮询

    当我在服务器中托管应用程序时 它会检查服务器端事件并始终回退到长轮询 服务器托管环境为Windows Server 2012 R1和IIS 7 5 无论如何 我们是否可以解决这个问题 https cloud githubuserconten
  • 模板类的不明确多重继承

    我有一个真实的情况 可以总结为以下示例 template lt typename ListenerType gt struct Notifier void add listener ListenerType struct TimeListe
  • 在 Xamarin Android 中将图像从 URL 异步加载到 ImageView 中

    我有一个包含多个项目的 ListView 列表中的每个项目都应该有一个与之关联的图像 我创建了一个数组适配器来保存每个列表项并具有我希望加载的图像的 url 我正在尝试使用 Web 请求异步加载图像 并设置图像并在加载后在视图中更新它 但视
  • C++ 求二维数组每一行的最大值

    我已经设法用这个找到我的二维数组的每一行的最小值 void findLowest int A Cm int n int m int min A 0 0 for int i 0 i lt n i for int j 0 j lt m j if
  • fgets() 和 Ctrl+D,三次才能结束?

    I don t understand why I need press Ctrl D for three times to send the EOF In addition if I press Enter then it only too
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • 跨多个控件共享事件处理程序

    在我用 C 编写的 Windows 窗体应用程序中 我有一堆按钮 当用户的鼠标悬停在按钮上时 我希望按钮的边框发生变化 目前我有以下多个实例 每个按钮一个副本 private void btnStopServer MouseEnter ob
  • 将字符串从非托管代码传递到托管

    我在将字符串从非托管代码传递到托管代码时遇到问题 在我的非托管类中 非托管类 cpp 我有一个来自托管代码的函数指针 TESTCALLBACK FUNCTION testCbFunc TESTCALLBACK FUNCTION 接受一个字符
  • 如何在 WPF RichTextBox 中跟踪 TextPointer?

    我正在尝试了解 WPF RichTextBox 中的 TextPointer 类 我希望能够跟踪它们 以便我可以将信息与文本中的区域相关联 我目前正在使用一个非常简单的示例来尝试弄清楚发生了什么 在 PreviewKeyDown 事件中 我
  • HttpClient 像浏览器一样请求

    当我通过 HttpClient 类调用网站 www livescore com 时 我总是收到错误 500 可能服务器阻止了来自 HttpClient 的请求 1 还有其他方法可以从网页获取html吗 2 如何设置标题来获取html内容 当
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • .Net Core / 控制台应用程序 / 配置 / XML

    我第一次尝试使用新的 ConfigurationBuilder 和选项模式进入 Net Core 库 这里有很多很好的例子 https docs asp net en latest fundamentals configuration ht
  • A* 之间的差异 pA = 新 A;和 A* pA = 新 A();

    在 C 中 以下两个动态对象创建之间的确切区别是什么 A pA new A A pA new A 我做了一些测试 但似乎在这两种情况下 都调用了默认构造函数 并且仅调用了它 我正在寻找性能方面的任何差异 Thanks If A是 POD 类
  • 像“1$”这样的位置参数如何与 printf() 一起使用?

    By man I find printf d width num and printf 2 1 d width num 是等价的 但在我看来 第二种风格应该与以下相同 printf d num width 然而通过测试似乎man是对的 为什
  • 在 URL 中发送之前对特殊字符进行百分比编码

    我需要传递特殊字符 如 等 Facebook Twitter 和此类社交网站的 URL 为此 我将这些字符替换为 URL 转义码 return valToEncode Replace 21 Replace 23 Replace 24 Rep
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var
  • 将变量分配给另一个变量,并将一个变量的更改反映到另一个变量中

    是否可以将一个变量分配给另一个变量 并且当您更改第二个变量时 更改会瀑布式下降到第一个变量 像这样 int a 0 int b a b 1 现在 b 和 a 都 1 我问这个问题的原因是因为我有 4 个要跟踪的对象 并且我使用名为 curr
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反

随机推荐

  • ChatGPT 打字机效果原理

    一 背景 在初次使用 ChatGPT 时 我就被打字机的视觉效果吸引 总是感觉似曾相识 因为经常在一些科幻电影中看到 高级文明回传的信息在通讯设备的屏幕上以打字机效果逐步出现 在紧张的氛围下 输出人类可读的内容 拉动着观众的神经 一步步将故
  • IDM下载百度资源出现403的解决方法

    IDM下载百度资源出现403的解决方法 参考文章 1 IDM下载百度资源出现403的解决方法 2 https www cnblogs com aucy p 9567375 html 备忘一下
  • redis的五种数据结构

    reids官方命令集查询 http redis io commands redis整合各种语言案例查询 https github com josiahcarlson redis in action redis可以存储键和五种不同类型的值之间
  • 《Java面向对象程序设计》学习笔记

    最近备考某学校的 817程序设计Java 的专业课 在学习耿祥义老师的 Java面向对象程序设计 第3版 微课视频版 发一些自己的学习笔记到专栏 一篇文章对应书上一章 可能不会及时更新 见谅 笔记可能有错误 看看就得 现在懒得浓缩精炼了 以
  • RL

    Catalogue DQN Framework Application 1 1 Cartpole Introduction 1 2 Code 1 3 Result Reference DQN Framework The agent inte
  • Java 遍历集合时删除元素 快速失败和安全失败

    文章目录 遍历集合时删除元素 遍历集合时删除元素的五种操作 方式4分析 方式2和方式3分析 方式5分析 方式1分析 方式5再分析 快速失败和安全失败 快速失败 fail fast 安全失败 fail safe 附录 遍历集合时删除元素 遍历
  • Visual Studio 调试系列1 Debug 与 Release 模式

    系列目录 已更新最新开发文章 点击查看详细 Debug 模式 Debug 通常称为调试版本 它包含调试信息 并且不作任何优化 便于程序员调试程序 在Debug模式下调试 可以在断点处看到详细的调试提示信息 如下图 并且在输出目录中生成 De
  • vue3+ts使用websocket 实现实时推送消息

    因业务需要 做大屏页面某一处需要不断推送消息 采用websocket技术 1 新建socket ts 在utils文件夹下新建socket ts export default class Socket cb 存储回调函数 construct
  • 程序员会被 AI 替代吗?

    作者 阿文 责编 伍杏玲 出品 程序人生 coder life 程序人生 编者按 本文作者是运维工程师 为什么拥有IT技能的他会自称为 客服 的呢 一起来看看吧 客服 日常 笔者目前从事云计算行业的客户服务性岗位 虽然工作上需要用到各种技术
  • import引css,@import引入CSS文件的方法

    import引入CSS文件的方法 发布时间 2020 09 26 13 58 39 来源 亿速云 阅读 61 作者 小新 小编给大家分享一下 import引入CSS文件的方法 相信大部分人都还不怎么了解 因此分享这篇文章给大家参考一下 希望
  • Excel使用hlookup和offset实现动态查询报表

    文章目录 1 筛选器 2 hLookUp函数 3 sum offset函数 4 mod函数 效果图 数据源 文件下载 https download csdn net download diyangxia 85231108 1 筛选器 在年份
  • 排序

    桶排序 快 简单 但是浪费空间 memset num 0 sizeof num for int i 1 i lt n i scanf d t num t for int i 1000 i gt 1 i for int j 1 j lt a
  • 朴素贝叶斯(NaïveBayes)

    Author Silly 0903 Datawhale Na veBayes简介 基于贝叶斯方法 通过先验概率 计算并选择最大的后验概率 核心公式 P Y X
  • 脚本(自用)

    import pandas as pd import csv data1 pd read csv kong csv 必须添加header None 否则默认把第一行数据处理成列名导致缺失 data5 pd read csv kong11 c
  • Python中pass的作用

    空语句 do nothing 保证格式完整 保证语义完整 以if语句为例 在c或c java中 if true do nothing else do something 对应于python就要这样写 if true pass do noth
  • windows10域账号自动登录设置

    设置windows域账号自动登录 打开注册表regedit 打开HKEY LOCAL MACHINE SOFTWARE Microsoft Windows NT CurrentVersion Winlogon并设置AutoAdminLogo
  • Ecovadis审核之【4大模块 7项原则 21项标准议题】

    Ecovadis企业社会责任涵盖内容 评估标准 参考模型 Ecovadis认证审计 四大主题模块 1 环境 2 劳工与人权 3 商业道德 4 可持续采购 Ecovadis认证审计之21项企业社会责任 CSR 标准 当评估一个公司的企业社会责
  • MySQL中基于InnoDB引擎的锁

    共享锁和排他锁 InnoDB实现了标准的行级锁 共享锁和排他锁 共享锁允许持有锁的事务读取一行 排他锁允许持有锁的事务更新或者删除一行 如果一个事务T1持有对第r行的共享锁 那么对于其他不同事务T2对第r行的锁请求处理方法如下 T2对于共享
  • 【教程】HTML快速学习

    教程 html快速学习 备注 一 HTML概述 二 标签 tag 三 HTML格式 四 注释 根标签 头部标签 1 注释 2 根标签 3 常见头部标签 五 常见主体标签 1 文本标题标签 heading 2 段落标签 p 3 功能标签 4
  • C++实现生产者和消费者模型

    C 实现生产者和消费者模型 C 实现生产者和消费者模型 1 实现细节 2 单生产者 单消费者模型 3 单生产者 多消费者模型 4 多生产者 单消费者模型 5 多生产者 多消费者模型 参考 C 实现生产者和消费者模型 1 实现细节 具体的实现