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

Linux-----线程同步(资源竞争和同步锁)

目录

资源竞争(背景)

 锁(解决方式,实现同步)

互斥锁

读写锁

自旋锁


资源竞争(背景)

竞态条件

当多个线程并发访问和修改同一个共享资源(如全局变量)时,如果没有适当的同步措施,就会遇到线程同步问题。这种情况下,程序最终的结果依赖于线程执行的具体时序,导致了竞态条件。

竞态条件(race condition)是一种特定的线程同步问题,指的是两个或者以上进程或者线程并发执行时,其最终的结果依赖于进程或者线程执行的精确时序。它会导致程序的行为和输出超出预期,因为共享资源的最终状态取决于线程执行的顺序和时机。为了确保程序执行结果的正确性和预期一致,需要通过适当的线程同步机制来避免竞态条件。

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>#define COUNT 20000long long int num = 0;void* fun(void *arg) {for (int i = 0;i < 1000000;i++) { // 加100wnum++;}
}int main(int argc, char const* argv[])
{pthread_t tid[2];pthread_create(&tid[0], NULL, fun, NULL);pthread_create(&tid[1], NULL, fun, NULL);// 等待全部线程执行完成for (int i = 0;i < 2;i++) {pthread_join(tid[i], NULL);}printf("num的值是:%lld\n", num);return 0;
}

 两个线程使用同一个资源,出现资源竞争问题。

 锁(解决方式,实现同步)

如何避免竞态条件

上述程序如果想避免竞态条件,有下面两种解决方案:

  1. 避免多线程写入一个地址。
  2. 给资源加锁,使同一时间操作特定资源的线程只有一个。

方法1可以通过逻辑上组织业务逻辑实现,这里我们讲方法2。

想解决竞争问题,我们需要互斥锁——mutex。

常见的锁机制

锁主要用于互斥,即在同一时间只允许一个执行单元(进程或线程)访问共享资源。包括上面的互斥锁在内,常见的锁机制共有三种:

  1. 互斥锁(Mutex):保证同一时刻只有一个线程可以执行临界区的代码。
  2. 读写锁(Reader/Writer Locks):允许多个读者同时读共享数据,但写者的访问是互斥的。
  3. 自旋锁(Spinlocks):在获取锁之前,线程在循环中忙等待,适用于锁持有时间非常短的场景,一般是Linux内核使用。

互斥锁

pthread_mutex_t 是一个定义在头文件<pthreadtypes.h>中的联合体类型的别名,其声明如下。

typedef union
{struct __pthread_mutex_s __data;char __size[__SIZEOF_PTHREAD_MUTEX_T];long int __align;
} pthread_mutex_t;

pthread_mutex_t用作线程之间的互斥锁。互斥锁是一种同步机制,用来控制对共享资源的访问。在任何时刻,最多只能有一个线程持有特定的互斥锁。如果一个线程试图获取一个已经被其他线程持有的锁,那么请求锁的线程将被阻塞,直到锁被释放。

用途

  • 保护共享数据,避免同时被多个线程访问导致的数据不一致问题。
  • 实现线程间的同步,确保线程之间对共享资源的访问按照预定的顺序进行。

操作

  • 初始化(pthread_mutex_init):创建互斥锁并初始化。
  • 锁定(pthread_mutex_lock):获取互斥锁。如果锁已经被其他线程持有,调用线程将阻塞。
  • 尝试锁定(pthread_mutex_trylock):尝试获取互斥锁。如果锁已被持有,立即返回而不是阻塞。
  • 解锁(pthread_mutex_unlock):释放互斥锁,使其可被其他线程获取。
  • 销毁(pthread_mutex_destroy):清理互斥锁资源。
#include <pthread.h>
/*** @brief 获取锁,如果此时锁被占则阻塞* * @param mutex 锁* @return int 获取锁结果*/
int pthread_mutex_lock(pthread_mutex_t *mutex);/*** @brief 非阻塞式获取锁,如果锁此时被占则返回EBUSY* * @param mutex 锁* @return int 获取锁结果*/
int pthread_mutex_trylock(pthread_mutex_t *mutex);/*** @brief 释放锁* * @param mutex 锁* @return int 释放锁结果*/
int pthread_mutex_unlock(pthread_mutex_t *mutex);

pthread_mutex_lock

该函数用于锁定指定的互斥锁。如果互斥锁已经被其他线程锁定,调用此函数的线程将会被阻塞,直到互斥锁变为可用状态。这意味着如果另一个线程持有锁,当前线程将等待直到锁被释放。

成功时返回0;失败时返回错误码。

pthread_mutex_trylock

该函数尝试锁定指定的互斥锁。与pthread_mutex_lock不同,如果互斥锁已经被其他线程锁定,pthread_mutex_trylock不会阻塞调用线程,而是立即返回一个错误码(EBUSY)。

如果成功锁定互斥锁,则返回0;如果互斥锁已被其他线程锁定,返回EBUSY;其他错误情况返回不同的错误码。

pthread_mutex_unlock

该函数用于解锁指定的互斥锁。调用线程必须是当前持有互斥锁的线程;否则,解锁操作可能会失败。

成功时返回0;失败时返回错误码。

初始化互斥锁

PTHREAD_MUTEX_INITIALIZER是POSIX线程(Pthreads)库中定义的一个宏,用于静态初始化互斥锁(mutex)。这个宏为互斥锁提供了一个初始状态,使其准备好被锁定和解锁,而不需要在程序运行时显式调用初始化函数。

当我们使用PTHREAD_MUTEX_INITIALIZER初始化互斥锁时,实际上是将互斥锁设置为默认属性和未锁定状态。这种初始化方式适用于简单的同步问题,我们可以通过以下代码初始化互斥锁。

static pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;

案例(对上面那个资源竞争的代码稍作修改):

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* fun(void* arg) {for (int i = 0;i < 1000000;i++) { // 加100w// 获取锁pthread_mutex_lock(&mutex);num++;// 释放锁pthread_mutex_unlock(&mutex);}
}

读写锁

读操作:在读写锁的控制下,多个线程可以同时获得读锁。这些线程可以并发地读取共享资源,但它们的存在阻止了写锁的授予。

写操作:如果至少有一个读操作持有读锁,写操作就无法获得写锁。写操作将会阻塞,直到所有的读锁都被释放。

pthread_rwlock_t

typedef union
{struct __pthread_rwlock_arch_t __data;char __size[__SIZEOF_PTHREAD_RWLOCK_T];long int __align;
} pthread_rwlock_t;

 pthread_rwlock_init()

/*** @brief 为rwlock指向的读写锁分配所有需要的资源,并将锁初始化为未锁定状态。读写锁的属性由attr参数指定,如果attr为NULL,则使用默认属性。当锁的属性为默认时,可以通过宏PTHREAD_RWLOCK_INITIALIZER初始化,即* pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; 效果和调用当前方法并为attr传入NULL是一样的* * @param rwlock 读写锁* @param attr 读写锁的属性* @return int 成功则返回0,否则返回错误码*/
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);

pthread_rwlock_destroy()

#include <pthread.h>/*** @brief 销毁rwlock指向的读写锁对象,并释放它使用的所有资源。当任何线程持有锁的时候销毁锁,或尝试销毁一个未初始化的锁,结果是未定义的。* * @param rwlock * @return int */
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

 pthread_rwlock_rdlock()​​​​​​​

/*** @brief 应用一个读锁到rwlock指向的读写锁上,并使调用线程获得读锁。如果写线程持有锁,调用线程无法获得读锁,它会阻塞直至获得锁。* * @param rwlock 读写锁* @return int 成功返回0,失败返回错误码*/
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

 ​​​​​​​pthread_rwlock_wrlock()

/*** @brief 应用一个写锁到rwlock指向的读写锁上,并使调用线程获得写锁。只要任意线程持有读写锁,则调用线程无法获得写锁,它将阻塞直至获得写锁。* * @param rwlock 读写锁* @return int 成功返回0,失败返回错误码*/
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

 ​​​​​​​pthread_rwlock_unlock()

/*** @brief 释放调用线程锁持有的rwlock指向的读写锁。* * @param rwlock 读写锁* @return int 成功返回0.失败返回错误码*/
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

案例: 

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>pthread_rwlock_t rwlock;
int shared_data = 0;void* lock_reader(void* args) {// 读写锁中的读是可以多个线程同时读取的// 获取读锁pthread_rwlock_rdlock(&rwlock);printf("%s读取到:%d\n", (char*)args, shared_data);pthread_rwlock_unlock(&rwlock);free(args);
}void* lock_writer(void* args) {// 获取写锁pthread_rwlock_wrlock(&rwlock);sleep(1);shared_data++;printf("当前%s写入完毕,结果是%d\n", (char*)args, shared_data);// 释放写锁pthread_rwlock_unlock(&rwlock);
}int main(int argc, char const* argv[])
{// 动态初始化创建锁pthread_rwlock_init(&rwlock,NULL);pthread_t writer1, writer2;pthread_t read[10];// 写线程pthread_create(&writer1, NULL, lock_writer, "写线程1");pthread_create(&writer2, NULL, lock_writer, "写线程2");sleep(3);// 读线程for (int i = 0;i < 10;i++) {char* s = (char*)malloc(20 * sizeof(char));sprintf(s, "读线程%d", i);pthread_create(&read[i], NULL, lock_reader, s);}// 主线程等待pthread_join(writer1, NULL);pthread_join(writer2, NULL);for (int i = 0;i < 10;i++) {pthread_join(read[i], NULL);}pthread_rwlock_destroy(&rwlock);return 0;
}

​​​​​​​

要注意的是,线程的执行顺序是由操作系统内核调度的,其运行规律并不简单地为“先创建先执行”。

写饥饿

 

多次运行后,我们发现,此时读操作总是连续执行的,且读操作休眠未结束时,写操作会被阻塞。与工作原理相符:① 读操作可以并发执行,相互之间不必争抢锁,多个读操作可以同时获得读锁;② 只要有一个线程持有读写锁,写操作就会被阻塞。我们在读操作中加了1s休眠,只要有一个读线程获得锁,在1s内写操作是无法执行的,其它读操作就可以有充足的时间执行,因此读操作就会连续发生,写操作必须等待所有读操作执行完毕方可获得读写锁执行写操作。这就是使用读写锁时存在的潜在问题:写饥饿。

解决方法

① 问题描述

读写锁的写饥饿问题(Writer Starvation)是指在使用读写锁时,写线程可能无限期地等待获取写锁,因为读线程持续地获取读锁而不断地推迟写线程的执行。这种情况通常在读操作远多于写操作时出现。

② 解决方案

Linux提供了可以修改的属性pthread_rwlockattr_t,默认情况下,属性中指定的策略为“读优先”,当写操作阻塞时,读线程依然可以获得读锁,从而在读操作并发较高时导致写饥饿问题。我们可以尝试将策略更改为“写优先”,当写操作阻塞时,读线程无法获取锁,避免了写线程持有锁的时间持续延长,使得写线程获取锁的等待时间显著降低,从而避免写饥饿问题。

 pthread_rwlockattr_t

typedef union
{char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];long int __align;
} pthread_rwlockattr_t;

pthread_rwlockattr_init

#include <pthread.h>/*** @brief 用所有属性的默认值初始化attr指向的属性对象* * @param attr 读写锁属性对象指针* @return int 成功返回0,失败返回错误码*/
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);

pthread_rwlockattr_destroy

#include <pthread.h>/*** @brief 销毁读写锁属性对象* * @param attr 读写锁属性对象指针* @return int 成功返回0,失败返回错误码*/
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);

pthread_rwlockattr_setkind_np

#include <pthread.h>/*** @brief 将attr指向的属性对象中的"锁类型"属性设置为pref规定的值* * @param attr 读写锁属性对象指针* @param pref 希望设置的锁类型,可以被设置为以下三种取值的其中一种* PTHREAD_RWLOCK_PREFER_READER_NP: 默认值,读线程拥有更高优先级。当存在阻塞的写线程时,读线程仍然可以获得读写锁。只要不断有新的读线程,写线程将一直保持"饥饿"。* PTHREAD_RWLOCK_PREFER_WRITER_NP: 写线程拥有更高优先级。这一选项被glibc忽略。* PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP: 写线程拥有更高优先级,在当前系统环境下,它是有效的,将锁类型设置为该值以避免写饥饿。* @return int 成功返回0,失败返回非零的错误码*/
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref);

 案例:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>pthread_rwlock_t rwlock;
int shared_data = 0;void* lock_reader(void* args) {// 读写锁中的读是可以多个线程同时读取的// 获取读锁printf("%s开始获取读锁\n",(char*)args);pthread_rwlock_rdlock(&rwlock);printf("%s读取到:%d\n", (char*)args, shared_data);sleep(1);pthread_rwlock_unlock(&rwlock);free(args);
}void* lock_writer(void* args) {// 获取写锁printf("%s开始获取写锁\n",(char*)args);pthread_rwlock_wrlock(&rwlock);shared_data++;printf("当前%s写入完毕,结果是%d\n", (char*)args, shared_data);// 释放写锁pthread_rwlock_unlock(&rwlock);
}int main(int argc, char const* argv[])
{// 创建写锁属性对象pthread_rwlockattr_t attr;pthread_rwlockattr_init(&attr);// 设置写线程优先级pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);// 动态初始化创建锁pthread_rwlock_init(&rwlock,&attr);pthread_t writer1, writer2;pthread_t read[10];// 写线程pthread_create(&writer1, NULL, lock_writer, "写线程1");// 读线程for (int i = 0;i < 10;i++) {char* s = (char*)malloc(20 * sizeof(char));sprintf(s, "读线程%d", i);pthread_create(&read[i], NULL, lock_reader, s);if (i == 4) {pthread_create(&writer2, NULL, lock_writer, "写线程2");}}// 主线程等待pthread_join(writer1, NULL);pthread_join(writer2, NULL);for (int i = 0;i < 10;i++) {pthread_join(read[i], NULL);}pthread_rwlock_destroy(&rwlock);pthread_rwlockattr_destroy(&attr);return 0;
}

可以看到,写线程是先于读线程的。 不会像前面那样,出现写饥饿问题。

自旋锁

(我们写的用户锁一般是要尽量避免空转的,而对于自旋锁是属于操作系统内核的锁,不需要像用户锁那样去避免空转) 

在Linux内核中,自旋锁是一种用于多处理器系统中的低级同步机制,主要用于保护非常短的代码段或数据结构,以避免多个处理器同时访问共享资源。自旋锁相对于其他锁的优点是它们在锁被占用时会持续检查锁的状态(即“自旋”),而不是让线程进入休眠。这使得自旋锁在等待时间非常短的情况下非常有效,因为它避免了线程上下文切换的开销。

自旋锁主要用于内核模块或驱动程序中,避免上下文切换的开销。不能在用户空间使用。

相关文章:

Linux-----线程同步(资源竞争和同步锁)

目录 资源竞争&#xff08;背景&#xff09; 锁&#xff08;解决方式&#xff0c;实现同步&#xff09; 互斥锁 读写锁 自旋锁 资源竞争&#xff08;背景&#xff09; 竞态条件 当多个线程并发访问和修改同一个共享资源&#xff08;如全局变量&#xff09;时&#xff0c;…...

当当网书籍信息爬虫

1.基本理论 1.1概念体系 网络爬虫又称网络蜘蛛、网络蚂蚁、网络机器人等&#xff0c;可以按照我们设置的规则自动化爬取网络上的信息&#xff0c;这些规则被称为爬虫算法。是一种自动化程序&#xff0c;用于从互联网上抓取数据。爬虫通过模拟浏览器的行为&#xff0c;访问网页…...

React实现拖拽特效

前言 最近&#xff0c;我看到一个工程师的个人网站上&#xff0c;采用了拖拽作品集的互动特效&#xff0c;既有趣又吸引眼球。经过一些研究&#xff0c;我发现其实借助一些现成的套件&#xff0c;就能轻松实现这样的效果。今天就带大家一起看看&#xff0c;如何通过 Framer Mo…...

【竞技宝】LOL:ning直播再次锐评

北京时间1月18日,目前英雄联盟LPL2025正在如火如荼的进行之中,很多队伍都已经打完了新赛季的首场比赛,其中就包括AL战队,AL在休赛期进行了大幅度的人员调整,整体实力相比之前增强了不少,在16日的比赛中,AL3-0轻松击败LGD拿下了赛季开门红,而AL的打野选手tarzan在本场比赛中表现…...

ThreeJS能力演示——界面点选交互能力

1、支持界面点选 点选模型整体思路是&#xff1a;根据camera位置作为起始点&#xff0c;叠加鼠标相对位置作为偏置&#xff0c;摄像头方向作为射线方向。 根据射线方向中的遇到的3D物体列表&#xff0c;第一个遇到的物体作为被点选的物体。 // 鼠标事件处理let selectedObjec…...

flutter的web页面

有几个服务器 有几个后台 直接通过web端进去虽然说很方便&#xff0c;但… 于是把web页面镶嵌到应用里面去&#xff0c; 这样就换了个方式打开web页面了 比如这里有有个列表 这里是写死了&#xff0c;活的列表可以通过io去获取 import package:flutter/material.dart; imp…...

2025.1.17——三、SQLi regexp正则表达式|

题目来源&#xff1a;buuctf [NCTF2019]SQLi1 目录 一、打开靶机&#xff0c;整理信息 二、解题思路 step 1&#xff1a;正常注入 step 2&#xff1a;弄清关键字黑名单 1.目录扫描 2.bp爆破 step 3&#xff1a;根据过滤名单构造payload step 4&#xff1a;regexp正则注…...

虚幻基础2:gameplay框架

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 ue框架&#xff1a;gameplay组成game modeactorcomponent player controllergame state 工作流程 ue框架&#xff1a;gameplay 组成 game mode 游戏类型和规则。可以控制游戏的开始与结束以及一些其他功能。 ac…...

使用 Go 语言生成样式美观的 PDF 文件

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…...

鸿蒙-点击Notification通知并打开App的具体页面

意图通知 获取router事件中传递参数并跳转 目前点击通知消息打开应用的指定页面&#xff0c;通过为通知添加行为意图的方式。也就是在wants的parameters中设置自定义参数&#xff0c;然后在UIAbility的onNewWant或者onCreate方法中 解析配置的自定义参数信息判断跳转不同页面&a…...

非科班转码第5年零241天

文章目录 非科班转码第5年零241天第一份工作鸭梨山大同事的帮助第二份工作新公司学到很多出海计划 非科班转码第5年零241天 第一份工作 2019年5月24日&#xff0c;我从机械工程转码后找到第一份工作——图像算法工程师&#xff0c;能得到这份工作纯属偶然&#xff0c;当时公司…...

数据库:MongoDB命令行帮助解释

MongoDB命令&#xff1a; mongodmongosmongoperrormongoexportmongofilesmongoimportmongorestoreMongostat MongoDB包中的核心组件包括: mongod 是 MongoDB 的核心服务器进程&#xff0c;负责数据存储和管理。mongos 是分片集群的路由进程&#xff0c;负责将请求路由到正确…...

MongoDB单机版安装

MongoDB单机版安装 在CentOS Linux release 7.9.2009 (Core)下安装MongoDB的步骤如下&#xff1a; 1 创建用户和组&#xff08;可选&#xff0c;根据需要&#xff09; 如果您希望以非root用户运行MongoDB服务&#xff0c;可以创建一个专用的用户和组。 groupadd mongodb us…...

Azure面试

文章目录 项目地址一、Azure Storage1. What are the benefits of Azure Storage&#xff1f; 二、汇总 项目地址 教程作者&#xff1a;教程地址&#xff1a; 代码仓库地址&#xff1a; 所用到的框架和插件&#xff1a; dbt airflow一、Azure Storage 1. What are the bene…...

在.NET用C#将Word文档转换为HTML格式

将Word文档转换为HTML格式尤其具有显著的优势&#xff0c;它不仅能够确保文档内容在多种设备和平台上保持一致灵活的显示&#xff0c;还便于通过网络进行传播和集成到各种Web应用中。随着越来越多的企业和开发者寻求更灵活、更具兼容性的文件处理方式&#xff0c;.NET框架下的C…...

macOS 安装JDK17

文章目录 前言介绍新特性下载安装1.下载完成后打开downloads 双击进行安装2.配置环境变量3.测试快速切换JDK 小结 前言 近期找开源软件&#xff0c;发现很多都已经使用JDK17springboot3 了&#xff0c;之前的JDK8已经被替换下场&#xff0c;所以今天就在本机安装了JDK17&#…...

Django SimpleUI 自定义功能实战

1. 引言 Django SimpleUI 是一个基于 Django 的后台管理界面美化工具,旨在帮助开发者快速构建现代化的后台管理系统。除了默认的功能外,SimpleUI 还支持高度自定义,开发者可以根据需求添加各种实用功能。本文将详细介绍如何在 Django SimpleUI 中实现自定义功能,包括数据同…...

C语言/C++自然序列重排列——相邻序号不相邻问题⭐

同类题目&#xff1a;C语言自然序列重排——相邻元素的差值集合恰好有 k 个不同的值。⭐⭐-CSDN博客 题目描述&#xff08;难度⭐&#xff09; 一场针对 n 学生的考试将在一个又长又窄的房间里举行&#xff0c;因此学生们将按某种顺序排成一行。老师怀疑相邻编号的学生&#xf…...

Spring boot面试题---- Spring boot项目运行原理

1.启动流程概述 Spring Boot 的启动是从一个带有main方法的主类开始的。这个主类通常会有一个@SpringBootApplication注解。这个注解是一个组合注解,它包含了@Configuration、@EnableAutoConfiguration和@ComponentScan。@Configuration注解表明这个类是一个配置类,它可以定义…...

Qt/C++ 基于 QGraphicsView 的绘图软件 (附源码下载链接)

基于 Qt 的 QGraphicsView 绘图软件项目进行深入讲解&#xff0c;分析其核心代码与功能实现&#xff0c;帮助开发者理解 QGraphicsView 的用法。 项目概览 该项目实现了一个简单的绘图应用&#xff0c;用户可以在界面中创建和编辑矩形、椭圆、直线、多边形和文本等图形对象。功…...

如何使用 useMemo 和 memo 优化 React 应用性能?

使用 useMemo 和 memo 优化 React 应用性能 在构建复杂的 React 应用时&#xff0c;性能优化是确保应用流畅运行的关键。React 提供了多种工具来帮助开发者优化组件的渲染和计算逻辑&#xff0c;其中 useMemo 和 memo 是两个非常有用的 Hook。本文将详细介绍这两个工具的使用方…...

数据结构(链表 哈希表)

在Python中&#xff0c;链表和哈希表都是常见的数据结构&#xff0c;可以用来存储和处理数据。 链表是一种线性数据结构&#xff0c;由一系列节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。链表可以用来实现栈、队列以及其他数据结构。Python中可…...

人工智能之深度学习_[4]-神经网络入门

神经网络基础 1 神经网络 深度学习神经网络就是大脑仿生&#xff0c;数据从输入到输出经过一层一层的神经元产生预测值的过程就是前向传播&#xff08;也叫正向传播&#xff09;。 前向传播涉及到人工神经元是如何工作的&#xff08;也就是神经元的初始化、激活函数&#xf…...

STM32之CubeMX图形化工具开发介绍(十七)

STM32F407 系列文章 - STM32CubeMX&#xff08;十七&#xff09; 目录 前言 一、CubeMX 二、下载安装 1.下载 2.安装 3.图解步骤 三、用户界面 1.项目配置 2.项目生成 3.项目文件解释 4.新建工程 5.查看原工程 四、FAQ 总结 前言 STMCube源自意法半导体&#xf…...

css3过渡总结

一、过渡的定义与作用 CSS3 过渡&#xff08;Transitions&#xff09;允许 CSS 属性在一定的时间区间内平滑地过渡&#xff0c;从一个值转变为另一个值。它能够让网页元素的状态变化更加自然、流畅&#xff0c;给用户带来更好的视觉体验。例如&#xff0c;当一个元素从隐藏状态…...

latin1_swedish_ci(latin1 不支持存储中文、日文、韩文等多字节字符)

文章目录 1、SHOW TABLE STATUS WHERE Name batch_version;2、latin1_swedish_ci使用场景注意事项修改字符集和排序规则修改表的字符集和排序规则修改列的字符集和排序规则修改数据库的默认字符集和排序规则 3、ALTER TABLE batch_version CONVERT TO CHARACTER SET utf8mb4 C…...

C语言编程笔记:文件处理的艺术

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文一、为什么要用文件二、文件的分…...

[创业之路-255]:《华为数字化转型之道》-1-主要章节、核心内容、核心思想

目录 前言&#xff1a;数字化转型对于企业而言&#xff0c;是一种全方位的变革 一、主要章节 1、认知篇&#xff08;第1~2章&#xff09;- Why 2、方法篇&#xff08;第3~5章&#xff09;- How 3、实践篇&#xff08;第6~10章&#xff09;- 实践 4、平台篇&#xff08;第…...

《汽车维修技师》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答&#xff1a; 问&#xff1a;《汽车维修技师》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《汽车维修技师》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;北方联合出版传媒&#xff08;…...

2024 京东零售技术年度总结

每一次回望&#xff0c;都为了更好地前行。 2024 年&#xff0c;京东零售技术在全面助力业务发展的同时&#xff0c;在大模型应用、智能供应链、端技术、XR 体验等多个方向深入探索。京东 APP 完成阶段性重要改版&#xff0c;打造“又好又便宜”的优质体验&#xff1b;国补专区…...

如何在网站上做支付功能/网站提交

在想cocos适配之前&#xff0c;我们想想网页是怎么适配的。浏览器有各种规格&#xff0c;网页的一般做法是&#xff1a;背景图片铺满&#xff0c;网页内容保持在背景图片上居中&#xff0c;就实现了适应或者适配。css一般这样&#xff1a; .bg{ height:582px; background-image…...

智恒企业网站管理系统/网站是怎么优化推广的

闪黑屏的原因主要是我们启动Activity的时候&#xff0c;需要跑完onCreate和onResume才会显示界面闪黑屏的原因主要是我们启动Activity的时候&#xff0c;需要跑完onCreate和onResume才会显示界面。也就是说需要处理一些数据后&#xff0c;才会显示。按照这种思路&#xff0c;是…...

网站制作网站建设/制作网站模板

开发项目的时候&#xff0c;表很多&#xff0c;是不可能一点点的自己去写xml &#xff0c;dao文件的&#xff0c;这里就需要用到代码的自动生成工具了。 第一步&#xff1a;导入jar包&#xff0c;当然&#xff0c;这之前&#xff0c;基本环境&#xff0c;像mybatis&#xff0c;…...

wordpress调用文章内容标签/百度sem是什么

本文将分以下几个小节来学习&#xff1a; Java的JavaScript脚本引擎脚本开发中涉及到的类和接口简介开发步骤脚本与java数据传递脚本执行上下文作用域方法的调用编译脚本作用域 上例中"ScriptContext.GLOBAL_SCOPE"就是作用域。 ScriptContext的属性以及Bindings接口…...

三网合一 做网站/seo自动推广工具

1. 问题现象 在对项目中的clickhouse数据库进行查询的时候&#xff0c;提示&#xff1a;Too many simultaneous queries&#xff0c;如下图&#xff1a; 2. 问题原因 根据以往数据库的使用经验&#xff0c;确定应该是当前正在执行的查询数过多&#xff0c;超过了数据库的最…...

网站建设的原则有哪些/百度怎么发帖做推广

2017年1月15日科技部面试题(科技部2017年面试阶段分为三天。第一天上午体检&#xff0c;下午英语和专业课;第二天&#xff0c;素质拓展为主&#xff0c;首先用15分钟分组、起名、选队长等&#xff0c;然后开始素质拓展活动&#xff0c;每个活动之后&#xff0c;都会让考生们分享…...