FT2000+低温情况下RTC守时问题

news2024/9/25 5:21:12

1、背景介绍

飞腾2000+芯片通过I2C连接一块RTC时钟芯片(BellingBL5372)来实现麒麟信安系统下后的守时功能。目前BIOS支持UEFI功能,BIOS上电后能获取RTC时间,并将时间写入相应的UEFI变量或内存区域,操作系统上电后使用UEFI的APIs来读取相应的RTC时间变量或内存区域。

2、问题描述

在低温情况下(-42度),发现BIOS有概率无法获取到RTC时间,导致写入UEFI变量写入失败,从而操作系统也无法获取正确时间,变成系统出厂时间(2019年9月3日),如下图为出错情况:

 

但其实RTC芯片是正常工作的,当恢复到常温后又能获取到正确的时间,如下图

 

问题表现为低温情况下RTC守时不准。

3、原因分析

上电时BIOS通过I2C去访问RTC时钟芯片,由于FT2000+芯片商业档工作范围为0-70度,在低温-42度情况下完全有可能工作不正常,尤其是刚上电的那十几秒内,此时的I2C有概率无法读到RTC时钟芯片,导致BIOS时间无法获取,进一步导致系统下守时失败。

解决RTC问题其实就是解决一个温度问题,确保在温度满足芯片工作范围的情况下去读取RTC时钟芯片,也就是将读取时间后移,让芯片工作一段时间温度达到0度后再去读取。

对系统来说,有两种获取RTC时间的方式,一种就是从BIOS UEFI空间中去获取,另一种是调用系统下的驱动直接去读取时间。明显第二种方法是在操作系统启动过程中了,读取时间后移,能确保读到正确的时间。

4、问题解决

明确了通过加载驱动来获取RTC时间,那就按照这个思路去实现即可。

首先,在BIOS中添加RTC设备,通过dtb的方式添加,如下:

&i2c0 {
	status = "ok";
	rtc@32 {
		compatible = "beilin,bl5372";
		reg = <0x32>;
		status = "ok";
	};
};

这样驱动就能和设备匹配上,驱动代码如下:

/*
 * An I2C driver for Beilin BL5372 RTC
 */

#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>

#define DEG 0

#define DRV_VERSION "2.0"

#define TIME24 0
#define RS5C_ADDR(R)		(((R) << 4) | 0)
#define RS5C372_REG_SECS	0
#define RS5C372_REG_MINS	1
#define RS5C372_REG_HOURS	2
#define RS5C372_REG_WDAY	3
#define RS5C372_REG_DAY		4
#define RS5C372_REG_MONTH	5
#define RS5C372_REG_YEAR	6
#define RS5C372_REG_TRIM	7
#define RS5C_REG_ALARM_A_MIN	8			/* or ALARM_W */
#define RS5C_REG_ALARM_A_HOURS	9
#define RS5C_REG_ALARM_A_WDAY	10

#define RS5C_REG_ALARM_B_MIN	11			/* or ALARM_D */
#define RS5C_REG_ALARM_B_HOURS	12
#define RS5C_REG_ALARM_B_WDAY	13			/* (ALARM_B only) */
#define RS5C_REG_CTRL1		14
#define RS5C_REG_CTRL2		15
#define DEVICE_ADDR        0x32	//0x5d

static unsigned rs5c_reg2hr(unsigned reg)
{
#if TIME24
	printk("<RTC> TIME24 0x%x\n",bcd2bin(reg & 0x3f));
	return bcd2bin(reg & 0x3f);
#else
	unsigned	hour;
	printk("<RTC> TIME12 0x%x\n",bcd2bin(reg & 0x1f));
	hour = bcd2bin(reg & 0x1f);
	if (hour == 12)
		hour = 0;
	if (reg & 0x20)
		hour += 12;
	printk("<RTC> TIME12 hour=%d\n",hour);
	return hour;
#endif
}

static unsigned rs5c_reg2mon(unsigned reg)
{
#if TIME24
	printk("<RTC> TIME24 0x%x\n",bcd2bin(reg & 0x3f));
	return bcd2bin(reg & 0x3f);
#else
	unsigned	month;
	printk("<RTC> TIME12 0x%x\n",bcd2bin(reg & 0x1f));
	month = bcd2bin(reg & 0x1f);
	if (month > 12)
		month -= 12;
	printk("<RTC> TIME12 hour=%d\n",month);
	return month;
#endif
}

static unsigned rs5c_hr2reg(unsigned hour)
{

#if TIME24
	printk("<RTC> TIME24 0x%x\n",bin2bcd(hour));
	return bin2bcd(hour);

#else
	if (hour > 12)
	{
		printk("<RTC> TIME12(>12) 0x%x\n",(0x20 | bin2bcd(hour - 12)));
		return 0x20 | bin2bcd(hour - 12);
	}
	if (hour == 12)
	{
		printk("<RTC> TIME12(==12) 0x%x\n",(0x20 | bin2bcd(12)));
		return 0x20 | bin2bcd(12);
	}
	if (hour == 0)
	{
		printk("<RTC> TIME12(==0) 0x%x\n",bin2bcd(12));
		return bin2bcd(12);
	}
	printk("<RTC> TIME12(<12) 0x%x\n",bin2bcd(hour));
	return bin2bcd(hour);
#endif
}

//-----------------------------------------------
static struct i2c_driver bl5372_driver;

struct bl5372 {
	struct rtc_device *rtc;
	struct device *dev;
	int irq;
 	/*
	unsigned char sec;
	unsigned char min;
	unsigned char hour;
	unsigned char week;
	unsigned char day;
	unsigned char month;
	unsigned int year;
	*/
};


static int i2c_write_bytes(struct i2c_client *client, uint8_t *data, uint16_t len)
{
        struct i2c_msg msg;
        int ret=-1;

        msg.flags = !I2C_M_RD;
        msg.addr = client->addr;
        msg.len = len;
        msg.buf = data;

        ret=i2c_transfer(client->adapter, &msg,1);
        return ret;
}

static int bl5372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
	struct bl5372 *bl5372 = i2c_get_clientdata(client);
	unsigned char buf[7] = { RS5C_ADDR(RS5C372_REG_SECS) };

	printk("<RTC>bsl5372_get_datetime\n");
	struct i2c_msg msgs[] = {
		{/* setup read ptr */
			.addr = client->addr,
			.flags = 0,/* write */
			.len = 1,
			.buf = buf
		},
		{/* read the sec,min,hour,week,day,month,year */
			.addr = client->addr,
			.flags = I2C_M_RD,/* read */
			.len = 7,
			.buf = buf
		},
	};

	//int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
	//@num: Number of messages to be executed.
	//ÕâÀïÓÐÁœžöÏûÏ¢£¬ msgs[]µÄŽóС
	/* read registers */
	if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
		dev_err(&client->dev, "%s: read error\n", __func__);
		return -EIO;
	}

	printk("<RTC> buf[2]=0x%x\n",buf[2]);
	tm->tm_sec = bcd2bin(buf[0] & 0x7f);
	tm->tm_min = bcd2bin(buf[1] & 0x7f);
	printk("<RTC> Get hour Label*****\n");
	tm->tm_hour = rs5c_reg2hr(buf[2]);
	tm->tm_mday = bcd2bin(buf[4] & 0x7f);
	tm->tm_wday = bcd2bin(buf[3] & 0x7f);
	printk("<RTC> Get month Label*****\n");
	//tm->tm_mon = rs5c_reg2hr(buf[5])-1;
	tm->tm_mon = rs5c_reg2mon(buf[5])-1;
	tm->tm_year = bcd2bin(buf[6] & 0x7f)+100;
	printk("<RTC>@GET1 year%d month%d mday%d wday%d hour%d min%d sec%d\n",tm->tm_year,tm->tm_mon,tm->tm_mday,tm->tm_wday,tm->tm_hour,tm->tm_min,tm->tm_sec);

#if 1
	//------------------------------------
	buf[0]= RS5C_ADDR(RS5C_REG_CTRL2);
	struct i2c_msg msgs2[] = {
		{/* setup read  */
			.addr = client->addr,
			.len = 1,
			.buf = buf
		},
		{/* read is_24hour */
			.addr = client->addr,
			.flags = I2C_M_RD,
			.len = 1,
			.buf = buf
		},
	};

	/* read registers */
	if ((i2c_transfer(client->adapter, msgs2, 2)) != 2) {
		dev_err(&client->dev, "%s: read error\n", __func__);
		return -EIO;
	}

	if(buf[0]&0x20)
	{
		printk("24小时\n");
		tm->tm_hour= (tm->tm_hour<24)? (tm->tm_hour):(24-tm->tm_hour);
	}
	else
	{
		tm->tm_hour=(tm->tm_hour<24)? (tm->tm_hour):(tm->tm_hour+24);
	//	tm->tm_mday=(tm->tm_mday<7)? (tm->tm_mday):(tm->tm_mday+8-24);
	//	tm->tm_hour=tm->tm_hour+8;
	}

#endif


	//tm->tm_hour= (tm->tm_hour<24)? (tm->tm_hour):(tm->tm_hour-24);
	/* the clock can give out invalid datetime, but we cannot return
	 * -EINVAL otherwise hwclock will refuse to set the time on bootup.
	 */
	printk("<RTC>@GET2 year%d month%d mday%d wday%d hour%d min%d sec%d\n",tm->tm_year,tm->tm_mon,tm->tm_mday,tm->tm_wday,tm->tm_hour,tm->tm_min,tm->tm_sec);
	if (rtc_valid_tm(tm) < 0)
		dev_err(&client->dev, "retrieved date/time is not valid.\n");

	return 0;
}

static int bl5372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
	struct bl5372 *bl5372 = i2c_get_clientdata(client);
	int i, err;
	unsigned char buf[7];
	printk("<RTC>####bl5372_set_datetime\n");
//------------------------------------
	buf[0]= RS5C_ADDR(RS5C_REG_CTRL2);
	struct i2c_msg msgs2[] = {
		{/* setup read  */
			.addr = client->addr,
			.len = 1,
			.buf = buf
		},
		{/* read is_24hour */
			.addr = client->addr,
			.flags = I2C_M_RD,
			.len = 1,
			.buf = buf
		},
	};

	/* read registers */
	if ((i2c_transfer(client->adapter, msgs2, 2)) != 2) {
		dev_err(&client->dev, "%s: read error\n", __func__);
		return -EIO;
	}


/*	if((buf[0]&0x20)== 0)
	{
		printk("RTC 12xiaoshi\n");rs5c_hr2reg
		buf[0] |= (1<<5);
		err = i2c_master_send(client, buf, 1);

	}
*/
	printk("<RTC>IN####year%d month%d mday%d wday%d hour%d min%d sec%d\n",tm->tm_year,tm->tm_mon,tm->tm_mday,tm->tm_wday,tm->tm_hour,tm->tm_min,tm->tm_sec);


//------------------------
	/* hours, minutes and seconds */
	buf[0] = bin2bcd(tm->tm_sec);
	buf[1] = bin2bcd(tm->tm_min);
	printk("<RTC> Set hour Label*****\n");
	buf[2] = rs5c_hr2reg(tm->tm_hour);
	buf[3] = bin2bcd(tm->tm_wday & 0x07); //week 0~6
	buf[4] = bin2bcd(tm->tm_mday);
	buf[5] = bin2bcd(tm->tm_mon)+1;// 0~11
	tm->tm_year -= 100;
	buf[6] = bin2bcd(tm->tm_year % 100);// start at 1900  2018=>118
//
printk("###########write data to rtc \n");

for(i=0;i<7;i++)
{
printk("buf[%d] is 0x%x\n",i,buf[i]);
}

  	err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_SECS),   buf[0]);
 	i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_MINS) ,  buf[1]);
	i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_HOURS) , buf[2]);
	i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_WDAY) ,  buf[3]);
	i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_DAY) ,   buf[4]);
	i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_MONTH) , buf[5]);
	i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_YEAR) ,  buf[6]);

	return 0;
}

#ifdef CONFIG_RTC_INTF_DEV
static int bl5372_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
	struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));
	struct rtc_time tm;

	switch (cmd) {
	case RTC_RD_TIME:
		//bl5372_get_datetime(to_i2c_client(dev), &tm);
		return 0;
	case RTC_SET_TIME:
		if (copy_from_user(&tm, arg, sizeof(tm)))
                        return -EFAULT;

		bl5372_set_datetime(to_i2c_client(dev), &tm);
		return 0;
	default:
		return -ENOIOCTLCMD;
	}

}
#else
#define bl5372_rtc_ioctl NULL
#endif

static int bl5372_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	return bl5372_get_datetime(to_i2c_client(dev), tm);
}

static int bl5372_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	return bl5372_set_datetime(to_i2c_client(dev), tm);
}

static int bl5372_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
	struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));
	return 0;
}

static int bl5372_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
	struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));
	return 0;
}

static int bl5372_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
        //struct bl5372 *bl5372 = dev_get_drvdata(dev);
	struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));

        return 0;
}

static const struct rtc_class_ops bl5372_rtc_ops = {
	.ioctl		= bl5372_rtc_ioctl,
	.read_time	= bl5372_rtc_read_time,
	.set_time	= bl5372_rtc_set_time,
	.read_alarm        = bl5372_rtc_getalarm,
    .set_alarm         = bl5372_rtc_setalarm,
    .alarm_irq_enable  = bl5372_rtc_alarm_irq_enable
};

static int bl5372_probe(struct i2c_client *client,
				const struct i2c_device_id *id)
{

	struct bl5372 *bl5372;

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
	{

		return -ENODEV;
	}
	bl5372 = devm_kzalloc(&client->dev, sizeof(struct bl5372),
				GFP_KERNEL);
	if (!bl5372)
	{

		return -ENOMEM;
	}
	device_init_wakeup(&client->dev, 1);

	i2c_set_clientdata(client, bl5372);

	bl5372->rtc = devm_rtc_device_register(&client->dev,
				bl5372_driver.driver.name,
				&bl5372_rtc_ops, THIS_MODULE);

	if (IS_ERR(bl5372->rtc))
	{
		return PTR_ERR(bl5372->rtc);
	}

	bl5372->rtc->uie_unsupported = 1;

	return 0;
}

static int bl5372_remove(struct i2c_client *client)
{

	return 0;
}

static const struct i2c_device_id bl5372_id[] = {
	{ "bl5372", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, bl5372_id);

#ifdef CONFIG_OF
static const struct of_device_id bl5372_of_match[] = {
	{ .compatible = "beilin,bl5372" },
	{}
};
MODULE_DEVICE_TABLE(of, bl5372_of_match);
#endif

static struct i2c_driver bl5372_driver = {
	.driver		= {
		.name	= "rtc-bl5372",
		.owner	= THIS_MODULE,
		.of_match_table = of_match_ptr(bl5372_of_match),
	},
	.probe		= bl5372_probe,
	.remove		= bl5372_remove,
	.id_table	= bl5372_id,
};

module_i2c_driver(bl5372_driver);

MODULE_AUTHOR("Zhengweiqing <1548889230@qq.com>");
MODULE_DESCRIPTION("Beilin BL5372 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);

下面是Makefile

obj-m +=rtc_bl5372.o

KDIR=/lib/modules/$(shell uname -r)/build

all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	make -C $(KDIR) M=$(PWD) clean

编译成ko,然后包进内核里面

将驱动编到内核里面后重新上电能发现系统下面有两个rtc设备,其中rtc0是系统采用BIOS UEFI方式产生的,rtc1是系统加载驱动产生的,如下图

 

由于系统时间默认采用的是从rtc0获取的时间,需要改为从rtc1(通过加载驱动产生的设备)获取时间。

在/etc/udev/rules.d下创建文件,这里命名为rtc1.rules

 

文件内容如下:

KERNEL=="rtc0",SYMLINK+="rtc_old"

KERNEL=="rtc1",SYMLINK+="rtc"

 

上述规则将原来命名为rtc0的设备链接到rtc old,将rtc1设备链接到rtc。这样,系统会将rtc1设备作为默认的时钟设备。

然后重新加载udev规则,使修改生效

udevadm control --reload-rules

重启系统即可。

重启后输入dmesg能看到后面又多出来一段内容,那就是配置系统时间时读取rtc1时间了:

 

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

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

相关文章

大模型基础02:GPT家族与提示学习

大模型基础&#xff1a;GPT 家族与提示学习 从 GPT-1 到 GPT-3.5 GPT(Generative Pre-trained Transformer)是 Google 于2018年提出的一种基于 Transformer 的预训练语言模型。它标志着自然语言处理领域从 RNN 时代进入 Transformer 时代。GPT 的发展历史和技术特点如下: GP…

产业园区数字孪生3d可视化全景展示方案

随着数字经济的发展&#xff0c;数字技术给企业发展带来了机遇的同时&#xff0c;也为企业管理带来挑战。比如园区运维&#xff0c;不仅体量大&#xff0c;复杂的运维管理系统&#xff0c;落地难度也较高。那么如何通过数字化手段重塑园区运营&#xff0c;打通园区各业务数据孤…

LimeReport设置当前打印时间

拉一个文本控件&#xff0c;然后填入下面信息&#xff1a; $S{ var curDate new Date(); var strYear curDate.getFullYear().toString(); var strMonth (curDate.getMonth() 1).toString(); var strDay curDate.getDate().toString(); var strHour curDate.getHours().…

句子变形金刚:变相的含义

一、说明 变形金刚完全重建了自然语言处理&#xff08;NLP&#xff09;的格局。在变形金刚出现之前&#xff0c;由于循环神经网络&#xff08;RNN&#xff09;&#xff0c;我们的翻译和语言分类很好——它们的语言理解能力有限&#xff0c;导致许多小错误&#xff0c;而且在大块…

mybatis-x插件的使用

mybatis-x能够帮助我们快速通过数据库生成实体类&#xff0c;mapper层&#xff0c;service层等 下面就带大家如何使用 首先我们去idea里面下载mybatis-x&#xff0c;如下图 我们还需要使用idea连接mysql数据库。效果如下图 接下来我们右键选中表&#xff0c;再选择第一项这个mm…

Panorama SCADA软件在无人值守水泵房的应用

应用背景 城市自来水公司、工矿企业的水泵房普遍数量较多&#xff0c;分布也较分散&#xff0c;在管理上通常会存在需要不定时开关泵、水泵故障不能及时发现、操作人员需24小时轮班值守、人员管理成本高等问题。 虹科Panorama是一个用于构建数据采集、SCADA 和历史解决方案的软…

华为云零代码新手教学-体验通过Astro Zero快速搭建微信小程序

您将会学到 您将学会如何基于Astro零代码能力&#xff0c;DIY开发&#xff0c;完成问卷、投票、信息收集、流程处理等工作&#xff0c;还能够在线筛选、分析数据。实现一站式快速开发个性化应用&#xff0c;体验轻松拖拽开发的乐趣。 您需要什么 环境准备 注册华为云账号、实…

【socket编程简述】TCP UDP 通信总结、TCP连接的三次握手、TCP断开的四次挥手

Socket&#xff1a;Socket被称做 套接字&#xff0c;是网络通信中的一种约定。 Socket编程的应用无处不在&#xff0c;我们平时用的QQ、微信、浏览器等程序.都与Socket编程有关。 三次握手 四次断开 面试可…

Android Selector 的使用

什么是 Selector&#xff1f; Selector 和 Shape 相似&#xff0c;是Drawable资源的一种&#xff0c;可以根据不同的状态&#xff0c;设置不同的图片效果&#xff0c;关键节点 < selector > &#xff0c;例如&#xff1a;我们只需要将Button的 background 属性设置为该dr…

k8s v1.27.4二进制部署记录

记录二进制部署过程 #!/bin/bash#升级内核 update_kernel() {rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.orgyum -y install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpmyum --disablerepo"*" --enablerepo"elrepo-kernel&q…

男装已成越南电商红海赛道,品牌如何突围?

据Metric最新数据&#xff0c;在越南电商市场&#xff0c;男装类目竞争相对激烈&#xff0c;在各大电商平台都已出现饱和迹象。然而&#xff0c;在这片竞争激烈的红海中&#xff0c;仍有品牌找准机会成功突围&#xff0c;为其他品牌提供经验借鉴。 越南男装电商竞争激烈&#…

每天一道leetcode:433. 最小基因变化(图论中等广度优先遍历)

今日份题目&#xff1a; 基因序列可以表示为一条由 8 个字符组成的字符串&#xff0c;其中每个字符都是 A、C、G 和 T 之一。 假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。 例如&#xff0c;&quo…

基于MFCC特征提取和GMM训练的语音信号识别matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 MFCC特征提取 4.2 Gaussian Mixture Model&#xff08;GMM&#xff09; 4.3. 实现过程 4.4 应用领域 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3…

Kubernetes网络模型

Kubernetes 用来在集群上运行分布式系统。分布式系统的本质使得网络组件在 Kubernetes 中是至关重要也不可或缺的。理解 Kubernetes 的网络模型可以帮助你更好的在 Kubernetes 上运行、监控、诊断你的应用程序。 网络是一个很宽泛的领域&#xff0c;其中有许多成熟的技术。对于…

iPhone(iPad)安装deb文件

最简单的方法就是把deb相关的文件拖入手机对应的目录&#xff0c;一般是DynamicLibraries文件夹 参考&#xff1a;探讨手机越狱和安装deb文件的几种方式研究 1、在 Mac 上安装 dpkg 命令 打包 deb 教程之在 Mac 上安装 dpkg 命令_xcode打包root权限deb_qq_34810996的博客-CS…

shopee物流怎么发货?Shopee新手发货流程解析!

在Shopee平台上开店是许多卖家的第一次尝试&#xff0c;因此他们可能会遇到shopee物流店铺长时间没有订单的情况&#xff0c;但一旦有订单&#xff0c;他们可能又不知道如何发货。下面我介绍shopee物流发货流程&#xff0c;帮助卖家更好地处理订单和发货。 ​首先&#xff0c;让…

easyx图形库基础:5.多物体运动+图片+消息处理

多物体运动图片帧率控制消息处理 一. 多物体运动1.如何合理的管理小球&#xff1a;2.初始化每一个球的信息&#xff1a;3.绘制多物体的运动&#xff1a;4.尝试添加小球个数&#xff1a;num10&#xff1a;![请添加图片描述](https://img-blog.csdnimg.cn/ce058e08c11c4410a7d09d…

线程|线程的使用、四种实现方式

1.线程的实现方式 1.用户级线程 开销小&#xff0c;用户空间就可以创建多个。缺点是&#xff1a;内核无法感知用户级多个线程的存在&#xff0c;把其当作只有一个线程&#xff0c;所以只会提供一个处理器。 2.内核级线程 相对于用户级开销稍微大一点&#xff0c;可以利用多…

【JavaSE】面向对象之继承

继承 继承概念继承的语法父类成员的访问子类和父类没有同名成员变量子类和父类有同名成员变量成员方法名字不同成员方法名字相同 super关键字子类构造方法super和this继承方式 继承概念 继承(inheritance)机制&#xff1a;是面向对象程序设计使代码可以复用的最重要的手段&…

分代收集 + 垃圾回收算法

分代假说 1. 弱分代假说&#xff08;Weak Generational Hypothesis&#xff09;&#xff1a;绝大多数对象都是朝生夕灭的 2. 强分代假说&#xff08;Strong Generational Hypothesis&#xff09;&#xff1a;熬过越多次垃圾收集过程的对象就越难以消亡 3. 跨代引用假说&…