驱动:中断底半部 platform平台总线

news2024/11/10 18:44:12

 

中断底半部实现方法:
1. 软中断
2. tasklet
3. workqueue 

解释 

workqueue和tasklet是Linux内核中用于处理中断后续任务的两种机制,它们在中断处理流程中扮演着重要的角色。下面是对它们的详细解释:

Tasklet

定义与作用
Tasklet是Linux内核中一种快速执行的单线程下半部(bottom half)处理机制。它的主要作用是在中断处理完成后,继续处理那些不应该在中断服务程序(ISR)中执行的时间消耗较大的任务。Tasklet是由softirq机制驱动的,能够在不同的CPU上并行执行,但它并不睡眠(即不会调用会导致当前线程睡眠的函数),这保证了其执行的高效性。

特点

  • 短小精悍:Tasklet的代码应当简短且高效,因为它不应该包含任何会显著延长执行时间的操作
  • 可以被打断:与其他中断处理过程类似,Tasklet的执行过程也可能被新的中断打断
  • 执行高效:由于Tasklet的设计初衷是为了快速执行,它通常能够非常高效地处理那些需要在中断服务程序之外完成的任务。

Workqueue

定义与作用
Workqueue是Linux内核中另一种用于执行耗时任务的机制。与Tasklet不同,Workqueue可以睡眠,即它可以在执行过程中 调用 可能导致 当前线程睡眠的函数。这使得Workqueue更加适合那些需要执行复杂或耗时操作的场景。

特点

  • 可以做耗时操作:由于Workqueue允许睡眠,因此它可以执行那些无法在中断服务程序或Tasklet中执行的耗时操作。
  • 灵活的执行:Workqueue的工作项可以被添加到不同的工作队列中,并根据需要进行调度执行。这使得Workqueue在处理多种类型的耗时任务时非常灵活。
  • 可以被硬中断打断:尽管Workqueue的执行可能会睡眠,但它仍然可以被硬中断打断。然而,在Workqueue中的任务被打断后内核会负责在适当的时候重新调度这些任务继续执行

为什么要加这个?

加入Tasklet和Workqueue这两种机制,主要是为了解决中断处理过程中的一个关键问题:如何在中断服务程序(ISR)中高效且安全地处理耗时任务。中断服务程序需要快速响应并尽可能快地完成处理,以避免影响系统的响应性。然而,在某些情况下,中断处理可能需要执行一些耗时较长的操作,这些操作如果直接在中断服务程序中执行,会显著增加中断的响应时间,并可能导致其他中断被延迟处理。通过引入Tasklet和Workqueue这两种机制,可以将耗时任务从中断服务程序中分离出来,并在系统的适当时候以异步的方式执行,从而在保证系统响应性的同时,完成这些必要的耗时操作。

新概念

中断上下文(代码):中断处理相关的 程序(中断服务程序、tasklet)
进程上下文:进程相关的程序(open、read、write)、workqueue ---->内核上的,不包括应用层的 

一、tasklet

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <asm-generic/errno-base.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/ioctl.h>

#define DEV_NAME "adc"
#define ADCCON 0x58000000
#define ADCDAT0 0x5800000C
#define CLKCON 0x4C00000C
static volatile unsigned long * adccon;
static volatile unsigned long * adcdat0;
static volatile unsigned long * clkcon;
static wait_queue_head_t wq;
static int condition = 0;
static struct tasklet_struct tsk;

#define ADC_MAGIC_NUM 'x'
#define ADC_SET_CHANNEL 2
#define CMD_ADC_SET_CHANNEL _IOW(ADC_MAGIC_NUM, ADC_SET_CHANNEL, unsigned char)

static void tasklet_handle(unsigned long arg)
{
	condition = 1;
	wake_up_interruptible(&wq);
	printk("tasklet_schedule  arg = %ld ...\n", arg);
}

static irqreturn_t irq_handler(int num, void * arg)
{
	tasklet_schedule(&tsk);
	printk("num = %d  arg = %d\n", num, *(int *)arg);
	return IRQ_HANDLED;
}

static void init_adc(void)
{
	*adccon = (1 << 14) | (49 << 6);
}

static void start_adc(void)
{
	*adccon |= (1 << 0);	
}

static unsigned short read_adc(void)
{
	unsigned short data = *adcdat0 & 0x3ff;
	return data;
}

static int set_channel(unsigned char channel)
{
	if(channel < 0 || channel > 7)
		return -EINVAL;

	*adccon &= ~(0x7 << 3);
	*adccon |= (channel <<3);

	return 0;
}

static int open (struct inode * inode, struct file * file)
{
	init_adc();
	printk("adc open ...\n");
	return 0;
}

static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
	//copy_to_user(buf, &value, sizeof(value));
	unsigned short value = 0;
	printk("adc read start ...\n");
	condition = 0;
	start_adc();	
	wait_event_interruptible(wq, condition);

	value = read_adc();
	copy_to_user(buf, &value, sizeof(value));
	printk("adc read ...\n");

	return sizeof(value);
}

static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{
	return 0;
}

static long ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{
	int ret = 0;
	unsigned char args = 0;

	switch(cmd)
	{
	case CMD_ADC_SET_CHANNEL:
		copy_from_user(&args, (unsigned char *)arg, _IOC_SIZE(CMD_ADC_SET_CHANNEL));
		ret = set_channel(args);
		break;
	default :
		ret = -EINVAL;
	}

	return ret;
}

static int close (struct inode * inode, struct file * file)
{
	printk("adc close ...\n");
	return 0;
}

static struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.unlocked_ioctl = ioctl,
	.release = close
};

static struct miscdevice misc = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEV_NAME,
	.fops = &fops
};

static int arg = 100;

static int __init adc_init(void)
{
	int ret = misc_register(&misc);
	if(ret < 0)
		goto err_misc_register;

	ret = request_irq(IRQ_ADC, irq_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, "adc_irq", &arg);	
	if(ret < 0)
		goto err_request_irq;

	adccon = ioremap(ADCCON, sizeof(*adccon));
	adcdat0 = ioremap(ADCDAT0, sizeof(*adcdat0));
	clkcon = ioremap(CLKCON, sizeof(*clkcon));

	*clkcon |= (1 << 15);
	printk("clkcon = 0x%lx\n", *clkcon);

	init_waitqueue_head(&wq);

	tasklet_init(&tsk, tasklet_handle, 200);

	printk("adc_init  ...\n");
	return ret;

err_misc_register:
	misc_deregister(&misc);
	printk("adc misc_register faiadc\n");	
	return ret;

err_request_irq:
	disable_irq(IRQ_ADC);
	free_irq(IRQ_ADC, &arg);
	return ret;
}

static void __exit adc_exit(void)
{
	iounmap(clkcon);
	iounmap(adcdat0);
	iounmap(adccon);
	disable_irq(IRQ_ADC);
	free_irq(IRQ_ADC, &arg);
	misc_deregister(&misc);
	printk("adc_exit  ###############################\n");
}

module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");

 

二、workqueue

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <asm-generic/errno-base.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/ioctl.h>
#include <linux/workqueue.h>
#include <linux/delay.h>

#define DEV_NAME "adc"
#define ADCCON 0x58000000
#define ADCDAT0 0x5800000C
#define CLKCON 0x4C00000C
static volatile unsigned long * adccon;
static volatile unsigned long * adcdat0;
static volatile unsigned long * clkcon;
static wait_queue_head_t wq;
static int condition = 0;
static struct work_struct work;

#define ADC_MAGIC_NUM 'x'
#define ADC_SET_CHANNEL 2
#define CMD_ADC_SET_CHANNEL _IOW(ADC_MAGIC_NUM, ADC_SET_CHANNEL, unsigned char)

static void work_handle(struct work_struct *work)
{
	condition = 1;
	ssleep(2);
	wake_up_interruptible(&wq);
	printk("work_handle  ...\n");
}

static irqreturn_t irq_handler(int num, void * arg)
{
	schedule_work(&work);
	printk("num = %d  arg = %d\n", num, *(int *)arg);
	return IRQ_HANDLED;
}

static void init_adc(void)
{
	*adccon = (1 << 14) | (49 << 6);
}

static void start_adc(void)
{
	*adccon |= (1 << 0);	
}

static unsigned short read_adc(void)
{
	unsigned short data = *adcdat0 & 0x3ff;
	return data;
}

static int set_channel(unsigned char channel)
{
	if(channel < 0 || channel > 7)
		return -EINVAL;

	*adccon &= ~(0x7 << 3);
	*adccon |= (channel <<3);

	return 0;
}

static int open (struct inode * inode, struct file * file)
{
	init_adc();
	printk("adc open ...\n");
	return 0;
}

static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
	//copy_to_user(buf, &value, sizeof(value));
	unsigned short value = 0;
	printk("adc read start ...\n");
	condition = 0;
	start_adc();	
	wait_event_interruptible(wq, condition);

	value = read_adc();
	copy_to_user(buf, &value, sizeof(value));
	printk("adc read ...\n");

	return sizeof(value);
}

static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{
	return 0;
}

static long ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{
	int ret = 0;
	unsigned char args = 0;

	switch(cmd)
	{
	case CMD_ADC_SET_CHANNEL:
		copy_from_user(&args, (unsigned char *)arg, _IOC_SIZE(CMD_ADC_SET_CHANNEL));
		ret = set_channel(args);
		break;
	default :
		ret = -EINVAL;
	}

	return ret;
}

static int close (struct inode * inode, struct file * file)
{
	printk("adc close ...\n");
	return 0;
}

static struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.unlocked_ioctl = ioctl,
	.release = close
};

static struct miscdevice misc = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEV_NAME,
	.fops = &fops
};

static int arg = 100;

static int __init adc_init(void)
{
	int ret = misc_register(&misc);
	if(ret < 0)
		goto err_misc_register;

	ret = request_irq(IRQ_ADC, irq_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, "adc_irq", &arg);	
	if(ret < 0)
		goto err_request_irq;

	adccon = ioremap(ADCCON, sizeof(*adccon));
	adcdat0 = ioremap(ADCDAT0, sizeof(*adcdat0));
	clkcon = ioremap(CLKCON, sizeof(*clkcon));

	*clkcon |= (1 << 15);
	printk("clkcon = 0x%lx\n", *clkcon);

	init_waitqueue_head(&wq);

	INIT_WORK(&work, work_handle);

	printk("adc_init  ...\n");
	return ret;

err_misc_register:
	misc_deregister(&misc);
	printk("adc misc_register faiadc\n");	
	return ret;

err_request_irq:
	disable_irq(IRQ_ADC);
	free_irq(IRQ_ADC, &arg);
	return ret;
}

static void __exit adc_exit(void)
{
	iounmap(clkcon);
	iounmap(adcdat0);
	iounmap(adccon);
	disable_irq(IRQ_ADC);
	free_irq(IRQ_ADC, &arg);
	misc_deregister(&misc);
	printk("adc_exit  ###############################\n");
}

module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");

三、platform平台总线

设备资源和驱动方法分开管理

 

device 

driver 

 


 vi drivers/char/adc_device.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm-generic/errno-base.h>
#include <linux/platform_device.h>
#include <mach/irqs.h>

#define DEV_NAME "adc"
#define ADCCON 0x58000000
#define ADCDAT0 0x5800000C
#define CLKCON 0x4C00000C
#define IRQ_NUM IRQ_ADC

static struct resource res[] = 
{
	[0] = 
	{
		.start = ADCCON,
		.end = ADCCON + 4 - 1,
		.name = "adccon",
		.flags = IORESOURCE_IO
	},
	[1] = 
	{
		.start = ADCDAT0,
		.end = ADCDAT0 + 4 - 1,
		.name = "adcdat0",
		.flags = IORESOURCE_IO
	},
	[2] = 
	{
		.start = CLKCON,
		.end = CLKCON + 4 - 1,
		.name = "clkcon",
		.flags = IORESOURCE_IO
	},
	[3] = 
	{
		.start = IRQ_NUM,
		.end = IRQ_NUM,
		.name = "irq_adc",
		.flags = IORESOURCE_IRQ
	}
};

static void	release(struct device *dev){}

static struct platform_device dev = 
{
	.name = DEV_NAME,
	.id = -1,
	.dev = 
	{
		.release = release	
	},
	.num_resources = sizeof(res) / sizeof(res[0]),
	.resource = res
};

static int __init adc_device_init(void)
{
	int ret = platform_device_register(&dev);
	if(ret < 0)
		goto err_platform_register;

	printk("platform_device_register ...\n");
	return 0;

err_platform_register:
	platform_device_unregister(&dev);
	printk("platform_device_register failed ...\n");
	return ret;
}

static void __exit adc_device_exit(void)
{
	platform_device_unregister(&dev);
	printk("platform_device_unregister  ...\n");
}

module_init(adc_device_init);
module_exit(adc_device_exit);
MODULE_LICENSE("GPL");

vi drivers/char/adc_driver.c

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <asm-generic/errno-base.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/ioctl.h>
#include <linux/platform_device.h>

#define DEV_NAME "adc"
static volatile unsigned long * adccon;
static volatile unsigned long * adcdat0;
static volatile unsigned long * clkcon;
static wait_queue_head_t wq;
static int condition = 0;
static int arg = 100;

#define ADC_MAGIC_NUM 'x'
#define ADC_SET_CHANNEL 2
#define CMD_ADC_SET_CHANNEL _IOW(ADC_MAGIC_NUM, ADC_SET_CHANNEL, unsigned char)

irqreturn_t irq_handler(int num, void * arg)
{
	printk("num = %d  arg = %d\n", num, *(int *)arg);
	condition = 1;
	wake_up_interruptible(&wq);
	return IRQ_HANDLED;
}

static void init_adc(void)
{
	*adccon = (1 << 14) | (49 << 6);
}

static void start_adc(void)
{
	*adccon |= (1 << 0);	
}

static unsigned short read_adc(void)
{
	unsigned short data = *adcdat0 & 0x3ff;
	return data;
}

static int set_channel(unsigned char channel)
{
	if(channel < 0 || channel > 7)
		return -EINVAL;

	*adccon &= ~(0x7 << 3);
	*adccon |= (channel <<3);

	return 0;
}

static int open (struct inode * inode, struct file * file)
{
	init_adc();
	printk("adc open ...\n");
	return 0;
}

static ssize_t read (struct file * file, char __user * buf, size_t len, loff_t * offset)
{
	//copy_to_user(buf, &value, sizeof(value));
	unsigned short value = 0;
	printk("adc read start ...\n");
	condition = 0;
	start_adc();	
	wait_event_interruptible(wq, condition);

	value = read_adc();
	copy_to_user(buf, &value, sizeof(value));
	printk("adc read ...\n");

	return sizeof(value);
}

static ssize_t write (struct file * file, const char __user * buf, size_t len, loff_t * offset)
{
	return 0;
}

static long ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{
	int ret = 0;
	unsigned char args = 0;

	switch(cmd)
	{
	case CMD_ADC_SET_CHANNEL:
		copy_from_user(&args, (unsigned char *)arg, _IOC_SIZE(CMD_ADC_SET_CHANNEL));
		ret = set_channel(args);
		break;
	default :
		ret = -EINVAL;
	}

	return ret;
}

static int close (struct inode * inode, struct file * file)
{
	printk("adc close ...\n");
	return 0;
}

static struct file_operations fops = 
{
	.owner = THIS_MODULE,
	.open = open,
	.read = read,
	.write = write,
	.unlocked_ioctl = ioctl,
	.release = close
};

static struct miscdevice misc = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEV_NAME,
	.fops = &fops
};

static int probe(struct platform_device * pdev)
{
	int ret = misc_register(&misc);
	if(ret < 0)
		goto err_misc_register;

	ret = request_irq(pdev->resource[3].start, irq_handler, IRQF_DISABLED, "adc_irq", &arg);	
	if(ret < 0)
		goto err_request_irq;

	adccon = ioremap(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1);
	adcdat0 = ioremap(pdev->resource[1].start, pdev->resource[1].end - pdev->resource[1].start + 1);
	clkcon = ioremap(pdev->resource[2].start, pdev->resource[2].end - pdev->resource[2].start + 1);
	*clkcon |= (1 << 15);

	init_waitqueue_head(&wq);

	printk("adc_probe  ...\n");
	return ret;

err_misc_register:
	misc_deregister(&misc);
	printk("adc misc_register failed\n");	
	return ret;

err_request_irq:
	disable_irq(pdev->resource[3].start);
	free_irq(pdev->resource[3].start, &arg);
	return ret;
}

static int remove(struct platform_device * pdev)
{
	iounmap(clkcon);
	iounmap(adcdat0);
	iounmap(adccon);
	disable_irq(pdev->resource[3].start);
	free_irq(pdev->resource[3].start, &arg);
	misc_deregister(&misc);
	printk("adc_remove  ...\n");

	return 0;
}

static struct platform_driver dri = 
{
	.probe = probe,
	.remove = remove,
	.driver = 
	{
		.name = DEV_NAME	
	}
};

static int __init adc_driver_init(void)
{
	int ret = platform_driver_register(&dri);
	if(ret < 0)
		goto err_platform_register;
	printk("adc platform_driver_register ...\n");
	return 0;

err_platform_register:
	platform_driver_unregister(&dri);
	printk("adc platform_driver_register failed\n");
	return ret;
}

static void __exit adc_driver_exit(void)
{
	platform_driver_unregister(&dri);
	printk("adc platform_driver_unregister ...\n");
}

module_init(adc_driver_init);
module_exit(adc_driver_exit);
MODULE_LICENSE("GPL");

应用层adc_app.c 

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>

#define ADC_MAGIC_NUM 'x'
#define ADC_SET_CHANNEL 2
#define CMD_ADC_SET_CHANNEL _IOW(ADC_MAGIC_NUM,ADC_SET_CHANNEL,unsigned char)

int main(int argc, const char *argv[])
{
	int fd = open("/dev/adc",O_RDWR);
	if(fd < 0)
	{
		perror("open fail");
		return -1;
	}
	unsigned char arg = 0;
	unsigned short value = 0;
	while(1)
	{
		arg = 0;
		int ret = ioctl(fd,CMD_ADC_SET_CHANNEL,&arg);
		printf("ioctl ret = %d\n",ret);
		ret = read(fd,&value,sizeof(value));
		float v = 3.3 * value / 1024.0;
		printf("ret= %d value = %d  v = %.3f\n",ret ,value,v);
		sleep(2);

		arg = 1;
		ret = ioctl(fd,CMD_ADC_SET_CHANNEL,&arg);
		printf("ioctl ret = %d\n",ret);
		ret = read(fd,&value,sizeof(value));
		v = 3.3 * value / 1024.0;
		printf("ret= %d value = %d  v = %.3f\n",ret ,value,v);
		sleep(2);
	}
	close(fd);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2079451.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue笔记总结(Xmind格式):第二天

Xmind鸟瞰图&#xff1a; 简单文字总结&#xff1a; vue知识总结&#xff1a; 创建vue脚手架&#xff1a; 1.安装Node.js&#xff1a;Vue CLI作为一个npm包&#xff0c;需要Node.js来安装和运行。 2.安装Vue CLI&#xff1a;cmd指令 npm install -g vue/cli 3.创…

【微前端】前端微服务框架对比和技术选型

文章目录&#xff1a; 目录 文章目录&#xff1a; 前言&#xff1a; 具体内容&#xff1a; 1.什么是微前端 2.使用微服务的场景&#xff1a; iframe方案的缺点&#xff1a; 3.主流微服务框架介绍 2.1 无界-腾讯 官网 github地址&#xff1a; 无界的运行模式 简单了…

git笔记:git常用命令备忘录

1、工作区域和文件状态 1.1、工作区域 git的数据管理分为四个区域&#xff1a; 工作区&#xff08;Working Directory&#xff09; 本地工作目录&#xff0c;是我们电脑上的目录&#xff0c;是我们实际编写代码的区域&#xff0c;修改完工作区的文件后可以使用git add命令将…

Web开发:在 try-catch 块中有效捕捉和记录日志的最佳实践

目录 一、控制台程序&#xff08;demo&#xff09; 二、封装方法 三、实现效果 一、控制台程序&#xff08;demo&#xff09; using System.Diagnostics;namespace Progaram {class Program{public class Student{public int Id { get; set; }public string Name { get; se…

DataWhale AI夏令营-《李宏毅深度学习教程》笔记

DataWhale AI夏令营-《李宏毅深度学习教程》笔记 第三章 深度学习基础补充一些基础临界点及其种类逃离临界点方法批量动量自适应学习率学习率调度 分类分类损失批量归一化 之前一直接触的LLM大模型做一些应用&#xff0c;或者传统的自然语言处理&#xff0c;都是直接拿别人的模…

坐牢第三十天(c++)

1.作业&#xff1a; 提示并输入一个字符串&#xff0c;统计该字符串中字母个数、数字个数、空格个数、其他字符的个数 #include <iostream> #include <stdio.h> #include <string> using namespace std; int main(int argc, char const *argv[]) {string st…

什么软件可以用平板远程控制电脑?

在当今快节奏的工作和生活中&#xff0c;使用平板远程控制电脑已成为一种便捷高效的办公方式。无论你是想随时随地访问办公室的电脑&#xff0c;还是需要在旅途中进行紧急工作任务&#xff0c;Splashtop都是你的不二选择。本文将介绍如何使用Splashtop通过平板远程控制电脑&…

谷粒商城实战笔记-260-商城业务-消息队列-可靠投递-消费端确认

文章目录 一,Ack消息确认机制简介1,简介2,两个常用的Api二,消费者端消息确认实战三,RabbitMQ可靠性保障总结1,生产者2,消费者一,Ack消息确认机制简介 消费者端的确认机制(ACK/NACK)是RabbitMQ中一种重要的特性,它允许消费者告知Broker它们是否成功处理了接收到的消息…

ARM32开发——(六)GPIO_USART通信原理

1. 串行通信和并行通信 1.1 串行通信 串行通信是一种数据传输的方式&#xff0c;它是指将数据按照一位一位的顺序依次发送和接收&#xff0c;常用于远距离通信、嵌入式系统和低带宽传输场景下。串行通信相对于并行通信而言&#xff0c;只需要传输一条数据线&#xff0c;相对简…

Cgroup Driver配置异常导致的节点k8s涉及到的pod无法启动问题的处理

文章目录 前言一、现象二、问题定位1.docker服务检查2.message日志检查3.检查Cgroup Driver的配置4.修改/etc/docker/daemon.json文件 总结 前言 Cgroup Driver配置异常导致的节点k8s涉及到的pod无法启动问题的处理。 同事有台云主机重启之后&#xff0c;发现k8s相关的pod全部…

优维er看网易云之崩:巨头稍息的一小步,行业前进的一大步

撰文&#xff1a;右耳失聪的左撇子 制图&#xff1a;脾气超好 8月19日&#xff0c;网易云当了半天的“网抑云”&#xff0c;不开玩笑&#xff0c;我认为这是一场&#xff1a;真技术滑铁卢。 和很多朋友一样&#xff0c;数字音乐早已经深度融入我的日常生活&#xff0c;而作为一…

xss-labs靶场通关详解(11-15关)

第11关 referer 进行抓包 添加referer:click me!" type"button" οnmοuseοver"alert(/xss/)进行放包 第12关 进行抓包 修改User Agent&#xff1a;click me!" type"button" οnmοuseοver"alert(/xss/)进行放包 第13关 抓包 修改C…

python列表去重,一行实现 太优雅~

今天咱们来聊聊在 Python 中如何优雅地实现列表去重。 这是一个非常经典的问题&#xff0c;虽然很多人都会&#xff0c;但如何更优雅的实现呢&#xff1f;这里有不少有趣的解决方法。话不多说&#xff0c;咱们直奔主题。 方法一&#xff1a;用 set 去重 先来看个最简单的方法…

C语言基础(二十一)

C语言中的链表是一种常见的数据结构&#xff0c;用于存储一系列的元素&#xff0c;但与数组不同的是&#xff0c;链表中的元素在内存中不是连续存储的。链表中的每个元素称为节点&#xff08;Node&#xff09;&#xff0c;每个节点包含两个部分&#xff1a;一部分是存储数据的数…

智能开发工具GoLand v2024.2全新发布——更好地支持Go框架和语言

GoLand 使 Go 代码的阅读、编写和更改变得非常容易。即时错误检测和修复建议&#xff0c;通过一步撤消快速安全重构&#xff0c;智能代码完成&#xff0c;死代码检测和文档提示帮助所有 Go 开发人员&#xff0c;从新手到经验丰富的专业人士&#xff0c;创建快速、高效、和可靠的…

美创科技荣获“中国数据安全领域最具商业合作价值企业”

近日&#xff0c;数据智能产业创新服务媒体“数据猿”联合上海大数据联盟正式发布《2024中国数据安全领域最具商业合作价值企业盘点》&#xff0c;美创科技凭借在数据安全领域专业领先能力&#xff0c;荣获“最具商业合作价值企业”。 《2024中国数据安全领域最具商业合作价值企…

【Qt】Qt系统 | Qt文件

文章目录 一. 输入输出设备类二. 文件读写类三. 文件和目录信息 文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库&#xff0c;提供了跨平台的文件操作能力&#xff0c;封装了很多关于文件的类&#xff0c;通过这些类能够对文件系统进行操作&#xff0c;如文件读写、文…

Ubuntu上搭建Nginx环境

1. 软件包下载 nginx下载地址 下载linux版本的nginx&#xff0c;如图圈示 2. 将下载好的软件包上传至Linux服务器 假设上传到 /opt/nginx 目录,进入目录 cd /opt/nginx解压&#xff0c;根据版本自行修改版本号 tar zxvf nginx-1.16.0.tar.gz3.安装 安装编译所需的依赖&a…

IGE-LIO:充分利用强度信息克服激光退化场景下的定位精度

更多优质内容&#xff0c;请关注公众号&#xff1a;智驾机器人技术前线 1.论文信息 论文标题&#xff1a;IGE-LIO: Intensity Gradient Enhanced Tightly-Coupled LiDAR-Inertial Odometry 作者&#xff1a;Ziyu Chen, Hui Zhu, Biao Yu, Chunmao Jiang, Chen Hua, Xuhui Fu a…

android openGL ES详解——深度缓冲区

一、深度缓冲区概念 深度缓存区是指一块专门内存区域&#xff0c;存储在显存中&#xff0c;用于存储屏幕上所绘制图形的每个像素点的深度值。深度值越大&#xff0c;离观察者越远。深度值越小&#xff0c;里观察者越近。 深度缓冲区与帧缓冲区相对应&#xff0c;用于记录上面…