线程同步(一)

news2024/12/25 23:47:47

上篇文章讲述了什么是线程,以及在Linux系统下线程的相关操作

 线程(Linux系统实现)_小梁今天敲代码了吗的博客-CSDN博客

本文将继续讲述线程的相关知识——线程同步

目录

1.线程同步的概念

2.线程不同步可能会发生什么

3.线程同步方式   

4.互斥锁

申请一个互斥锁

尝试获取互斥锁

互斥锁解锁

互斥锁示例

1.线程同步的概念

        线程同步是指在多线程编程中,为了保证多个线程按照某种特定的方式正确、有序地执行,需要进行线程间的协作与同步。在多线程编程中,当多个线程共享同一份资源时,由于线程的执行顺序是不确定的,因此会存在一些并发问题,如死锁、竞态条件、资源争用等问题。为了避免这些问题,需要对线程进行同步。线程同步实际上就是通过线程之间的协作,使得线程能够按照一定的顺序来访问共享资源,从而避免并发问题的发生。常用的线程同步机制有互斥锁、信号量、条件变量等。

2.线程不同步可能会发生什么

线程不同步可能会导致以下问题:

1. 竞态条件(Race Condition):多个线程同时访问、修改一份共享资源,可能会导致资源的状态不确定,进而导致程序出现逻辑错误,甚至崩溃。

2. 死锁(Deadlock):多个线程在等待对方释放锁,导致所有线程都无法继续执行,程序陷入死循环,最终可能会崩溃。

3. 饥饿(Starvation):某些线程可能因为无法获取资源而一直等待,导致无法正常执行,进而影响整个程序的性能。

4. 资源争用(Resource Contention):多个线程同时竞争同一份资源,导致资源的使用效率下降,总体性能降低。

示例:两个线程交替数数(每个线程数 50 个数,交替数到 100)

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

#define MAX 50
// 全局变量
int number;

// 线程处理函数
void* funcA_num(void* arg)
{
    for(int i=0; i<MAX; ++i)
    {
        int cur = number;
        cur++;
        usleep(10);
        number = cur;
        printf("Thread A, id = %lu, number = %d\n", pthread_self(), number);
    }

    return NULL;
}

void* funcB_num(void* arg)
{
    for(int i=0; i<MAX; ++i)
    {
        int cur = number;
        cur++;
        number = cur;
        printf("Thread B, id = %lu, number = %d\n", pthread_self(), number);
        usleep(5);
    }

    return NULL;
}

int main(int argc, const char* argv[])
{
    pthread_t p1, p2;

    // 创建两个子线程
    pthread_create(&p1, NULL, funcA_num, NULL);
    pthread_create(&p2, NULL, funcB_num, NULL);

    // 阻塞,资源回收
    pthread_join(p1, NULL);
    pthread_join(p2, NULL);

    return 0;
}

在linux系统中编译,运行结果:

[itliang@localhost ~]$ ./xctb
Thread B, id = 140388304152320, number = 1
Thread A, id = 140388312545024, number = 1
Thread B, id = 140388304152320, number = 2
Thread A, id = 140388312545024, number = 2
Thread B, id = 140388304152320, number = 3
Thread A, id = 140388312545024, number = 3
Thread B, id = 140388304152320, number = 4
Thread A, id = 140388312545024, number = 4
Thread B, id = 140388304152320, number = 5
Thread A, id = 140388312545024, number = 5
Thread B, id = 140388304152320, number = 6
Thread B, id = 140388304152320, number = 7
Thread A, id = 140388312545024, number = 6
Thread B, id = 140388304152320, number = 7
Thread A, id = 140388312545024, number = 7
Thread A, id = 140388312545024, number = 8
Thread B, id = 140388304152320, number = 9
Thread B, id = 140388304152320, number = 10
Thread A, id = 140388312545024, number = 9
Thread A, id = 140388312545024, number = 10
Thread B, id = 140388304152320, number = 11
Thread B, id = 140388304152320, number = 12
Thread A, id = 140388312545024, number = 11
Thread A, id = 140388312545024, number = 12
Thread B, id = 140388304152320, number = 13
Thread A, id = 140388312545024, number = 13
Thread B, id = 140388304152320, number = 14
Thread B, id = 140388304152320, number = 15
Thread A, id = 140388312545024, number = 14
Thread B, id = 140388304152320, number = 15
Thread A, id = 140388312545024, number = 15
Thread A, id = 140388312545024, number = 16
Thread B, id = 140388304152320, number = 17
Thread B, id = 140388304152320, number = 18
Thread A, id = 140388312545024, number = 17
Thread A, id = 140388312545024, number = 18
Thread B, id = 140388304152320, number = 19
Thread A, id = 140388312545024, number = 19
Thread B, id = 140388304152320, number = 20
Thread B, id = 140388304152320, number = 21
Thread A, id = 140388312545024, number = 20
Thread A, id = 140388312545024, number = 21
Thread B, id = 140388304152320, number = 22
Thread B, id = 140388304152320, number = 23
Thread A, id = 140388312545024, number = 22
Thread A, id = 140388312545024, number = 23
Thread B, id = 140388304152320, number = 24
Thread B, id = 140388304152320, number = 25
Thread A, id = 140388312545024, number = 24
Thread B, id = 140388304152320, number = 25
Thread A, id = 140388312545024, number = 25
Thread A, id = 140388312545024, number = 26
Thread B, id = 140388304152320, number = 27
Thread B, id = 140388304152320, number = 28
Thread A, id = 140388312545024, number = 27
Thread A, id = 140388312545024, number = 28
Thread B, id = 140388304152320, number = 29
Thread A, id = 140388312545024, number = 29
Thread B, id = 140388304152320, number = 30
Thread B, id = 140388304152320, number = 31
Thread A, id = 140388312545024, number = 30
Thread A, id = 140388312545024, number = 31
Thread B, id = 140388304152320, number = 32
Thread B, id = 140388304152320, number = 33
Thread A, id = 140388312545024, number = 32
Thread A, id = 140388312545024, number = 33
Thread B, id = 140388304152320, number = 34
Thread B, id = 140388304152320, number = 35
Thread A, id = 140388312545024, number = 34
Thread A, id = 140388312545024, number = 35
Thread B, id = 140388304152320, number = 36
Thread B, id = 140388304152320, number = 37
Thread A, id = 140388312545024, number = 36
Thread A, id = 140388312545024, number = 37
Thread B, id = 140388304152320, number = 38
Thread B, id = 140388304152320, number = 39
Thread A, id = 140388312545024, number = 38
Thread A, id = 140388312545024, number = 39
Thread B, id = 140388304152320, number = 40
Thread B, id = 140388304152320, number = 41
Thread A, id = 140388312545024, number = 40
Thread A, id = 140388312545024, number = 41
Thread B, id = 140388304152320, number = 42
Thread B, id = 140388304152320, number = 43
Thread A, id = 140388312545024, number = 42
Thread A, id = 140388312545024, number = 43
Thread B, id = 140388304152320, number = 44
Thread B, id = 140388304152320, number = 45
Thread A, id = 140388312545024, number = 44
Thread A, id = 140388312545024, number = 45
Thread B, id = 140388304152320, number = 46
Thread B, id = 140388304152320, number = 47
Thread A, id = 140388312545024, number = 46
Thread A, id = 140388312545024, number = 47
Thread B, id = 140388304152320, number = 48
Thread A, id = 140388312545024, number = 48
Thread B, id = 140388304152320, number = 49
Thread B, id = 140388304152320, number = 50
Thread A, id = 140388312545024, number = 49
Thread A, id = 140388312545024, number = 50

        通过对上面例子的测试,可以看出虽然每个线程内部循环了 50 次每次数一个数,但是最终没有数到 100,通过输出的结果可以看到,有些数字被重复数了多次,其原因就是没有对线程进行同步处理,造成了数据的混乱。

3.线程同步方式   

线程同步方式有以下几种:

1. 互斥锁(Mutex):使用互斥锁来控制多个线程对共享资源的访问。只有获得锁的线程才能进入临界区进行操作,其他线程必须等待锁释放后才能进入。

2. 读写锁(Read-Write Lock):允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。读写锁可以提高程序的并发性能,减少资源争用问题。

3. 条件变量(Condition Variable):用于等待特定条件的发生。当某个线程等待某个条件变量时,它会被阻塞,直到其他线程发出信号,通知条件变量已经满足。

4. 信号量(Semaphore):使用信号量来控制多个线程对有限数量资源的访问。信号量表示资源的数量,每个线程在使用完资源后必须释放信号量,以便其他线程可以使用资源。

以上是常见的几种线程同步方式,每种方式都有其适用的场景和优缺点,根据具体的应用场景选择适合的同步方式是非常重要的,这里先介绍互斥锁。

4.互斥锁

        互斥锁是线程同步最常用的一种方式,通过互斥锁可以锁定一个代码块,被锁定的这个代码块,所有的线程只能顺序执行 (不能并行处理),这样多线程访问共享资源数据混乱的问题就可以被解决了,需要付出的代价就是执行效率的降低,因为默认临界区多个线程是可以并行处理的,现在只能串行处理。

在 Linux 中互斥锁的类型为 pthread_mutex_t,创建一个这种类型的变量就得到了一把互斥锁:

pthread_mutex_t  mutex;

       在创建的锁对象中保存了当前这把锁的状态信息:锁定还是打开,如果是锁定状态还记录了给这把锁加锁的线程信息(线程 ID)。一个互斥锁变量只能被一个线程锁定,被锁定之后其他线程再对互斥锁变量加锁就会被阻塞,直到这把互斥锁被解锁,被阻塞的线程才能被解除阻塞。一般情况下,每一个共享资源对应一个把互斥锁,锁的个数和线程的个数无关。

Linux 提供的互斥锁操作函数如下,如果函数调用成功会返回 0,调用失败会返回相应的错误号:

// 初始化互斥锁
// restrict: 是一个关键字, 用来修饰指针, 只有这个关键字修饰的指针可以访问指向的内存地址, 其他指针是不行的
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
           const pthread_mutexattr_t *restrict attr);
// 释放互斥锁资源            
int pthread_mutex_destroy(pthread_mutex_t *mutex);


//mutex: 互斥锁变量的地址
//attr: 互斥锁的属性,一般使用默认属性即可,这个参数指定为 NULL

申请一个互斥锁

修改互斥锁的状态, 将其设定为锁定状态, 这个状态被写入到参数 mutex 中

int pthread_mutex_lock(pthread_mutex_t *mutex);

这个函数被调用,首先会判断参数 mutex 互斥锁中的状态是不是锁定状态:

        没有被锁定,是打开的,这个线程可以加锁成功,这个这个锁中会记录是哪个线程加锁成功
如果被锁定了,其他线程加锁就失败了,这些线程都会阻塞在这把锁上
当这把锁被解开之后,这些阻塞在锁上的线程就解除阻塞了,并且这些线程是通过竞争的方式对这把锁加锁,没抢到锁的线程继续阻塞

尝试获取互斥锁

        下面这个函数是尝试获取一个互斥锁。如果当前的锁没有被其他线程占用,则该函数会立即返回,线程成功获取锁,并返回0。否则,该函数会立即返回,线程不会阻塞,直接返回EBUSY错误码。

// 尝试加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);

        使用pthread_mutex_trylock函数获取锁的好处是,在获取锁的过程中不会引起线程阻塞,避免了由于长时间阻塞而导致的程序性能下降或死锁问题。但是,需要注意的是,在使用pthread_mutex_trylock函数时,如果获取锁失败,则需要有相应的处理措施来处理获取锁失败的情况。

互斥锁解锁

        通过调用pthread_mutex_unlock()函数将占用的互斥锁释放,以便其他线程可以竞争和访问共享资源。如果未正确解锁互斥锁,则可能会导致死锁或其他线程无法访问共享资源。因此,正确使用互斥锁是确保多线程代码正确运行的关键之一。

// 对互斥锁解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);

        我们可以将上面多线程交替数数的例子修改一下,使用互斥锁进行线程同步。两个线程一共操作了同一个全局变量,因此需要添加一互斥锁,来控制这两个线程。

互斥锁示例:

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

#define MAX 100
// 全局变量
int number;

// 创建一把互斥锁
// 全局变量, 多个线程共享
pthread_mutex_t mutex;

// 线程处理函数
void* funcA_num(void* arg)
{
    for(int i=0; i<MAX; ++i)
    {
        // 如果线程A加锁成功, 不阻塞
        // 如果B加锁成功, 线程A阻塞
        pthread_mutex_lock(&mutex);
        int cur = number;
        cur++;
        usleep(10);
        number = cur;
        pthread_mutex_unlock(&mutex);
        printf("Thread A, id = %lu, number = %d\n", pthread_self(), number);
    }

    return NULL;
}

void* funcB_num(void* arg)
{
    for(int i=0; i<MAX; ++i)
    {
        // a加锁成功, b线程访问这把锁的时候是锁定的
        // 线程B先阻塞, a线程解锁之后阻塞解除
        // 线程B加锁成功了
        pthread_mutex_lock(&mutex);
        int cur = number;
        cur++;
        number = cur;
        pthread_mutex_unlock(&mutex);
        printf("Thread B, id = %lu, number = %d\n", pthread_self(), number);
        usleep(5);
    }

    return NULL;
}

int main(int argc, const char* argv[])
{
    pthread_t p1, p2;

    // 初始化互斥锁
    pthread_mutex_init(&mutex, NULL);

    // 创建两个子线程
    pthread_create(&p1, NULL, funcA_num, NULL);
    pthread_create(&p2, NULL, funcB_num, NULL);

    // 阻塞,资源回收
    pthread_join(p1, NULL);
    pthread_join(p2, NULL);

    // 销毁互斥锁
    // 线程销毁之后, 再去释放互斥锁
    pthread_mutex_destroy(&mutex);

    return 0;
}


linux系统运行结果:

[itliang@localhost ~]$ ./xctb
Thread A, id = 139912715360000, number = 1
Thread A, id = 139912715360000, number = 2
Thread A, id = 139912715360000, number = 3
Thread A, id = 139912715360000, number = 4
Thread A, id = 139912715360000, number = 5
Thread A, id = 139912715360000, number = 6
Thread A, id = 139912715360000, number = 7
Thread A, id = 139912715360000, number = 8
Thread A, id = 139912715360000, number = 9
Thread A, id = 139912715360000, number = 10
Thread A, id = 139912715360000, number = 11
Thread A, id = 139912715360000, number = 12
Thread A, id = 139912715360000, number = 13
Thread A, id = 139912715360000, number = 14
Thread A, id = 139912715360000, number = 15
Thread A, id = 139912715360000, number = 16
Thread A, id = 139912715360000, number = 17
Thread A, id = 139912715360000, number = 18
Thread A, id = 139912715360000, number = 19
Thread A, id = 139912715360000, number = 20
Thread A, id = 139912715360000, number = 21
Thread A, id = 139912715360000, number = 22
Thread A, id = 139912715360000, number = 23
Thread A, id = 139912715360000, number = 24
Thread A, id = 139912715360000, number = 25
Thread A, id = 139912715360000, number = 26
Thread A, id = 139912715360000, number = 27
Thread A, id = 139912715360000, number = 28
Thread A, id = 139912715360000, number = 29
Thread A, id = 139912715360000, number = 30
Thread A, id = 139912715360000, number = 31
Thread A, id = 139912715360000, number = 32
Thread A, id = 139912715360000, number = 33
Thread A, id = 139912715360000, number = 34
Thread A, id = 139912715360000, number = 35
Thread A, id = 139912715360000, number = 36
Thread A, id = 139912715360000, number = 37
Thread A, id = 139912715360000, number = 38
Thread A, id = 139912715360000, number = 39
Thread A, id = 139912715360000, number = 40
Thread A, id = 139912715360000, number = 41
Thread A, id = 139912715360000, number = 42
Thread A, id = 139912715360000, number = 43
Thread A, id = 139912715360000, number = 44
Thread A, id = 139912715360000, number = 45
Thread A, id = 139912715360000, number = 46
Thread A, id = 139912715360000, number = 47
Thread A, id = 139912715360000, number = 48
Thread A, id = 139912715360000, number = 49
Thread A, id = 139912715360000, number = 50
Thread B, id = 139912706967296, number = 51
Thread B, id = 139912706967296, number = 52
Thread B, id = 139912706967296, number = 53
Thread B, id = 139912706967296, number = 54
Thread B, id = 139912706967296, number = 55
Thread B, id = 139912706967296, number = 56
Thread B, id = 139912706967296, number = 57
Thread B, id = 139912706967296, number = 58
Thread B, id = 139912706967296, number = 59
Thread B, id = 139912706967296, number = 60
Thread B, id = 139912706967296, number = 61
Thread B, id = 139912706967296, number = 62
Thread B, id = 139912706967296, number = 63
Thread B, id = 139912706967296, number = 64
Thread B, id = 139912706967296, number = 65
Thread B, id = 139912706967296, number = 66
Thread B, id = 139912706967296, number = 67
Thread B, id = 139912706967296, number = 68
Thread B, id = 139912706967296, number = 69
Thread B, id = 139912706967296, number = 70
Thread B, id = 139912706967296, number = 71
Thread B, id = 139912706967296, number = 72
Thread B, id = 139912706967296, number = 73
Thread B, id = 139912706967296, number = 74
Thread B, id = 139912706967296, number = 75
Thread B, id = 139912706967296, number = 76
Thread B, id = 139912706967296, number = 77
Thread B, id = 139912706967296, number = 78
Thread B, id = 139912706967296, number = 79
Thread B, id = 139912706967296, number = 80
Thread B, id = 139912706967296, number = 81
Thread B, id = 139912706967296, number = 82
Thread B, id = 139912706967296, number = 83
Thread B, id = 139912706967296, number = 84
Thread B, id = 139912706967296, number = 85
Thread B, id = 139912706967296, number = 86
Thread B, id = 139912706967296, number = 87
Thread B, id = 139912706967296, number = 88
Thread B, id = 139912706967296, number = 89
Thread B, id = 139912706967296, number = 90
Thread B, id = 139912706967296, number = 91
Thread B, id = 139912706967296, number = 92
Thread B, id = 139912706967296, number = 93
Thread B, id = 139912706967296, number = 94
Thread B, id = 139912706967296, number = 95
Thread B, id = 139912706967296, number = 96
Thread B, id = 139912706967296, number = 97
Thread B, id = 139912706967296, number = 98
Thread B, id = 139912706967296, number = 99
Thread B, id = 139912706967296, number = 100

 

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

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

相关文章

机器学习——聚类算法详解

1.聚类问题 1&#xff09;聚类问题与核心概念 聚类算法做的事情&#xff0c;就是对无标签的数据&#xff0c;基于数据分布进行分群分组&#xff0c;使得相似的数据尽量落在同一个簇内。 我们先对比区分一下聚类和分类&#xff1a; 聚类是一种无监督学习&#xff0c;而分类是…

第十三届蓝桥杯C++B组j国赛

第十三届蓝桥杯C组 题目 2693: 蓝桥杯2022年第十三届决赛真题-卡牌 题目描述 这天&#xff0c;小明在整理他的卡牌。 他一共有 n 种卡牌&#xff0c;第 i 种卡牌上印有正整数数 i(i ∈ [1, n])&#xff0c;且第 i 种卡牌 现有 ai 张。 而如果有 n 张卡牌&#xff0c;其中…

硬件测试—温升测试之JinKo 多路温度测试仪使用说明

一、概述 1.1&#xff1a;测试概述 在硬件测试中&#xff0c;温升测试也是很重要的一项测试&#xff0c;产品各项器件在稳定的环境温度下满载工作的芯片温度&#xff0c;根据测试情况评估散热需求。 1.2&#xff1a;产品图片 1.3&#xff1a;使用设备 名称 厂家 型号 PC电脑…

Acer Aspire V3-572G电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件配置 硬件型号驱动情况 主板Acer Aspire V3-572G 处理器i7 5500U 2 Cores/4 Threads2,4Ghz已驱动 内存Any Samsung, Hynix or Kingston DDR3 8GB(4GBx2).已驱动 硬…

CSDN 每日一练用例数据缺失了怎么办?

CSDN 每日一练用例数据缺失了怎么办&#xff1f; 引子1、用例与结果不匹配2、阅读理解困难3、用例数据缺失 用例数据缺失&#xff0c;却有人 AC &#xff1f;神奇的 c28761 津津的储蓄计划70093 近视的小张 小结最后的吐槽 引子 老顾最近几个月经常在 CSDN 举办的周赛上浑水摸…

Tomcat 部署

一.Tomcat介绍 Servlet 是 Java Servlet 的简称&#xff0c;可以理解为是一个服务连接器&#xff0c;是用 Java 编写的服务器端程序&#xff0c;具有独立于平台和协议的特性&#xff0c; 简单的理解&#xff1a;servlet 就是一个中间件&#xff0c;包含了接口和方法&#xff0…

5.2.6 地址解析协议ARP

5.2.6 地址解析协议ARP 我们知道要想实现全球范围内主机之间的通信&#xff0c;必须要有两个统一&#xff0c;一个是地址&#xff0c;另一个是数据格式&#xff0c;我们使用IP地址来实现统一的地址&#xff0c;使用IP分组实现统一的数据格式&#xff0c;在前面局域网的学习中我…

【AIGC】13、GLIP | 首次将 object detection 重建为 phrase grounding 任务

文章目录 一、背景二、方法2.1 将 object detection 和 phrase grounding 进行统一2.2 Language-aware deep fusion2.3 使用语义丰富的数据来进行预训练 三、效果3.1 迁移到现有 Benchmarks3.2 在 COCO 上进行零样本和有监督的迁移3.3 在 LVIS 上进行零样本迁移学习3.4 在 Flic…

android 如何分析应用的内存(四)

android 如何分析应用的内存&#xff08;四&#xff09; 接上文 在介绍细节部分时&#xff0c;先介绍了各种工具的使用&#xff0c;而这些工具&#xff0c;大部分都用来调试&#xff0c;诸如&#xff1a;特定内存点&#xff0c;堆栈&#xff0c;寄存器&#xff0c;变量值等的…

MySQL安装流程 及 8.0与5.7区别

一、MySQL版本介绍 1、MySQL 8.0 窗口函数&#xff1a;MySQL 8.0版本支持窗口函数&#xff0c;这是数据分析工作中非常常用的一类函数。窗口函数可以让用户在单个查询中跨多个行检索数据&#xff0c;并在查询结果中对数据执行计算。隐藏索引&#xff1a;在MySQL 8.0版本中&am…

C++STL详解 string【C++】

文章目录 函数模板函数模板的原理函数模板的实例化模板参数的匹配原则 类模板类模板的定义格式类模板的实例化 string 函数模板 函数模板的原理 template <typename T> //模板参数 ——类型 void Swap(T& x1, T& x2) {T tmp x1;x1 x2;x2 tmp; } int main()…

牛客网语法刷题篇(C语言) — 输出格式化

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paperjie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C语言—语法篇》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c;…

解析Linux中断子系统之中断映射

中断是当前计算机系统的基础功能&#xff0c;也是系统响应外设事件的必备桥梁。不同的架构对中断控制器有不同的设计理念&#xff0c;本文针对ARM公司提供的通用中断控制器&#xff08;GIC,Generic Interrupt Controller&#xff09;介绍在linux系统中的硬件中断号与软件中断号…

SpringBootWeb登录认证

1. 登录功能 1.1 需求 在登录界面中&#xff0c;我们可以输入用户的用户名以及密码&#xff0c;然后点击 “登录” 按钮就要请求服务器&#xff0c;服务端判断用户输入的用户名或者密码是否正确。如果正确&#xff0c;则返回成功结果&#xff0c;前端跳转至系统首页面。 1.2 …

简单聊一聊数据库驱动

数据库驱动通常是数据库厂家提供的&#xff0c;他们按照jdbc协议对自家数据库封装了一套可对外调用的API。在应用程序和数据库之间起到了桥接的作用。它是一个软件组件&#xff0c;提供了与特定数据库系统进行通信的接口和功能。 1. 数据库驱动的作用&#xff1a; 连接数据库&…

AAOS 音频动态路由

文章目录 基本概念车载音频配置文件外部的配置音频区的方式车载音频服务配置路由流程框架中获取可用输出设备配置例子测试方法相关问题 基本概念 Android 管理来自 Android 应用的声音&#xff0c;同时控制这些应用&#xff0c;并根据其声音类型将声音路由到 HAL 中的输出设备…

FastAPi上传文件报错,There was an error parsing the body

问题描述 通过postman调用fastapi编写的文件接口报错&#xff0c;如下图&#xff1a; {"detail": "There was an error parsing the body" } 问题的解决过程 postman本身的问题 postman有个work directory的概念&#xff0c;所以再使用postman上传的文…

Git常用命令submodule

Git常用命令submodule 1、需求 当程序比较大参与开发人员较多时&#xff0c;代码管理就复杂起来。代码如果全员可见&#xff0c;可以创建 share 分支维护共用代 码&#xff0c;可以创建 core 分支维护核心算法代码&#xff0c;各进程分别占一个分支&#xff0c;定期同步 sha…

如何从 OpenAI 迁移到 Azure OpenAI(保姆级教程,包含如何兼容 JS 语言版 LangChain)

Azure OpenAI 和 OpenAI 一样&#xff0c;本质都是调用 api&#xff0c;Azure OpenAI 的使用会稍微复杂一点&#xff0c;但好处就是方便付费。 创建 Azure OpenAI 资源 首先&#xff0c;先登录 Azure 账号&#xff1a;https://azure.microsoft.com/zh-cn/ 接着创建 OpenAI 资…

硬件工程师-BOOST升压电源设计

一、Boost变换原理 开关闭合时&#xff0c;电感电压等于输入电压 开关断开时&#xff0c;电感电压输出电压-输入电压&#xff0c; 电感的感生电动势&#xff0c;N ΔΦ磁通的变化率&#xff0c;Δt时间 假设开关闭合与开关断开&#xff0c;开关断开时能量全部释放光 将第三个式…