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

共享栈 线程局部存储 线程互斥 线程同步 消费者生产者模型

共享栈  第一个主线程会在栈区  而当其他线程创建时实在共享区动态申请的栈区  

线程局部存储 __thread 关键字 与编译有关

全局变量是被线程共享的 每个线程都能看到 修改 但是如果对该全局变量加上__thread关键字后 该全局变量就不会被共享   将变量在库中的每一个线程的属性集合中都会添加一份 访问时用的是自己属性中的变量地址  这样每个线程访问的地址不同也就不会起冲突了

  类本身就是一个全局变量

在共享区动态创建的共享栈是不会动态向下生长的 是固定大小8M  通过mmap调用穿件stack

线程互斥 

补充概念 

共享资源:多个线程可以访问的资源。

临界资源:多线程执⾏流共享的资源就叫做临界资源

 临界区:每个线程内部,访问临界资源的代码,就叫做临界区

 互斥:任何时刻,互斥保证有且只有⼀个执⾏流进⼊临界区,访问临界资源,通常对临界资源起 保护作⽤

 原⼦性(后⾯讨论如何实现):不会被任何调度机制打断的操作,该操作只有两态,要么完成, 要么未完成

互斥量mutex

互斥量 是一种同步机制,用于保护共享资源,确保同一时间只有一个线程可以访问或修改该资源。互斥量是多线程编程中最常用的同步工具之一,广泛应用于各种编程语言和环境中。

线程访问的操作本身就不是原子性的 

计算可以分为逻辑计算和算术计算

执行中 1.--操作 虽然代码只有一句话 但是CPU在处理时会将其分为多个指令  先将变量读入寄存器中  读到算术运算符之后 在对寄存器中内容进行进行算术运算 在将计算后的内容放回  所以它并不具有原子性

2.if判断 也是不具有原子性的  这里if判断是一种逻辑计算 CPU在处理时会将其分为多个指令  先将变量读入寄存器 之后执行逻辑判断 之后根据逻辑判断执行逻辑分支  所以也不具有原子性

在线程工作中有些现场会被减到负数 或者在一个时间中突然增大 这是因为在线程操作时不具有原子性  导致可能同一时间中多个线程同时访问造成的结果

线程或进程什么时候会进行切换

a.时间片耗尽

b.有更高优先级的时间片要调度  

c.通过sleep 当从内核返回用户时 会检测时间片是否到达  从而导致切换  也就是在sleep的过程中 也会有其它线程来使用你的时间片 (这是对a的补充)

一条--指令的执行大概有三步

1. 数据->寄存器(本质 将数据从共享变成线程私有)(寄存器的内容 是执行流(线程)硬件上下文)

2.CPU内部运算

3.写回数据

可以看到在一个--的运算操作中时不能保证原子性的 所以应该怎么去解决这个问题呢?

代码必须要有互斥⾏为:

1.当代码进⼊临界区执⾏时,不允许其他线程进⼊该临界区。

2.如果多个线程同时要求执⾏临界区的代码,并且临界区没有线程在执⾏,那么只能允许⼀个线程 进⼊该临界区。

3.如果线程不在临界区中执⾏,那么该线程不能阻⽌其他线程进⼊临界区。

要做到这三点,本质上就是需要⼀把锁。Linux上提供的这把锁叫互斥量。

解决方案1. 加锁解锁

锁是全局的 所以锁也是共享资源 

初始化互斥量的接口

静态分配: 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

动态分配:

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const 
pthread_mutexattr_t *restrict attr);参数:mutex:要初始化的互斥量attr:NULL

销毁互斥量 销毁互斥量需要注意:

• 使⽤ PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁

• 不要销毁⼀个已经加锁的互斥量

• 已经销毁的互斥量,要确保后⾯不会有线程再尝试加锁

int pthread_mutex_destroy(pthread_mutex_t *mutex);

互斥量加锁和解锁 

int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex); 
返回值:成功返回0,失败返回错误号

调⽤ pthread_ lock 时,可能会遇到以下情况:

• 互斥量处于未锁状态,该函数会将互斥量锁定,同时返回成功

• 发起函数调⽤时,其他线程已经锁定互斥量,或者存在其他线程同时申请互斥量,但没有竞争到 互斥量,那么pthread_lock调⽤会陷⼊阻塞(执⾏流被挂起),等待互斥量解锁。

1.锁本身就是共享的 那么锁要交给谁来保护? 将lock 和 unlock 设置为原子性

2.如何看待锁 信号量(二元信号量 == 锁) 在信号量中我们说本质就是去预定资源  这里我们的锁就是将资源看做一个大整体 去加锁预定它 使用整个资源

3.申请锁 如果互斥量已经被拿走使用 那么当前线程就要进行阻塞等待 直到使用加锁的线程释放之后  所有当前正在等待的线程在一起竞争这个锁

4如果加锁后的线程被切换 这个锁仍旧使用的状态 其他线程依旧无法使用 也就是串行 也就是加锁执行效率低的原因

5.可不可以不遵守锁的规则  由于锁的出现本身就是为了程序的安全 不遵守会导致更容易出现bug

加锁就是对临界区加锁  

还有一种接口是非阻塞加锁  pthread_lock_trylock()

如果是全局锁 就没必要进行初始化 和人销毁  如果是局部锁就有必要  

互斥量(锁)的原理实现

  互斥量的原理主要在于swap和exchange指令  当我们的代码在汇编链接之后 最后会在加锁的部分就会出现swap和exchange 所以我们在平时时看不到的   该指令的作用是将内存单元和寄存器的数据进行交换 swap或是exchange都是一条指令所以可以保证原子性  在刚开始我们的mutex是存在在内存单元的 而当需要加锁 swap或是exchange就会将其交换到寄存器  我们的内存单元就变为了0(在刚开始寄存器是0 )  之后得到锁的线程开始执行临界区任务 结束之后将锁释放 也就是将其从自己的寄存器在交换会内存单元 而在这一过程中 其他线程是无法得到锁的 (因为这时内存单元为0  其他线程中的寄存器中也是0)

这样就实现了锁的原子性(这个工作是软件实现)

但是其实我们的硬件也是可以实现的  我们线程调度是要受到时钟中断的影响 是时钟中断在推动着系统工作 如果我们通过硬件进行关中断 (关闭时钟和外部中断) 这样就可以保证一个正在访问临界区线程的原子性

纯互斥可解决大部分安全问题 但是并不一定合理

比如在一个自习室只有一个座位一把钥匙 也就是只能有一个人用这个自习室 而其他人就只能在门外等待钥匙释放后进行争夺  可是如果这个拿着钥匙的在释放钥匙又立马争夺钥匙 那么在门外等地啊的人就永远不可能 拿到那是使用这个自习室资源  这也就是饥饿 问题

那么我们该如何解决饥饿问题呢 ?

  同步  条件变量 

也就是在上面的例子中在外面等待的人不在通过争夺获取钥匙 而是在外面排队 当释放资源的人出来后 就必须排队队列的最后等待再次获取钥匙  这样每个人都有访问临界资源的机会也就不会导致饥饿 

条件变量

 • 当⼀个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。

 • 例如⼀个线程访问队列时,发现队列为空,它只能等待,只到其它线程将⼀个节点添加到队列 中。这种情况就需要⽤到条件变量。

同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从⽽有效避免 饥饿问题,叫做同步

条件变量的初始化 销毁 等待 释放 接口

1. 初始化条件变量

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
  • 功能:初始化一个条件变量。

  • 参数

    • cond:指向要初始化的条件变量的指针。

    • attr:指向条件变量属性的指针。如果为 NULL,则使用默认属性。

  • 返回值

    • 成功时返回 0

    • 失败时返回错误码,例如:

      • EINVALcondattr 无效。

      • EBUSYcond 已经被初始化。

2. 销毁条件变量

int pthread_cond_destroy(pthread_cond_t *cond);
  • 功能:销毁一个条件变量,释放与之相关的资源。

  • 参数

    • cond:指向要销毁的条件变量的指针。

  • 返回值

    • 成功时返回 0

    • 失败时返回错误码,例如:

      • EBUSY:有线程正在等待该条件变量。

 3. 等待条件变量

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
  • 功能:使线程等待某个条件变量满足。调用此函数时,线程会释放互斥锁(mutex),进入等待状态。当条件变量被唤醒时,线程会重新获取互斥锁并继续执行。

  • 参数

    • cond:要等待的条件变量。

    • mutex:与条件变量关联的互斥锁。调用此函数之前,必须先锁定该互斥锁。

  • 返回值

    • 成功时返回 0

    • 失败时返回错误码,例如:

      • EINVALcondmutex 无效。

      • EDEADLK:尝试获取互斥锁时发生死锁。

4. 唤醒所有等待条件变量的线程

int pthread_cond_broadcast(pthread_cond_t *cond);
  • 功能:唤醒所有正在等待该条件变量的线程。

  • 参数

    • cond:指向要唤醒的条件变量的指针。

  • 返回值

    • 成功时返回 0

    • 失败时返回错误码,例如:

      • EINVALcond 无效。

int pthread_cond_signal(pthread_cond_t *cond);

  • cond:指向要操作的条件变量的指针。该条件变量必须已经通过 pthread_cond_init 初始化(或者使用静态初始化器 PTHREAD_COND_INITIALIZER)。

  • 唤醒单个等待线程pthread_cond_signal 会唤醒一个正在等待该条件变量的线程。如果当前没有线程正在等待该条件变量,则调用此函数不会有任何效果。

  • 线程选择:具体唤醒哪个线程由线程库的调度策略决定,通常与线程的优先级和等待时间有关。

返回值

  • 成功时返回 0

  • 失败时返回错误码,例如:

    • EINVALcond 参数无效。

初始化信号量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
  • 功能:初始化一个信号量。

  • 参数

    • sem:指向信号量对象的指针。

    • pshared:控制信号量是线程间共享还是进程间共享。0 表示线程间共享,非零值表示进程间共享。

    • value:信号量的初始值,表示可用资源的数量。

  • 返回值

    • 成功时返回 0

    • 失败时返回 -1 并设置 errno 以指示错误原因。

销毁信号量

int sem_destroy(sem_t *sem);
  • 功能:销毁一个已经初始化的信号量,释放相关资源。

  • 参数

    • sem:指向要销毁的信号量对象的指针。

  • 返回值

    • 成功时返回 0

    • 失败时返回 -1 并设置 errno

等待信号量(P操作)

int sem_wait(sem_t *sem); // P()
  • 功能:等待信号量,如果信号量的值大于 0,则将其减 1 并立即返回;如果信号量的值为 0,则线程挂起(阻塞),直到信号量的值大于 0

  • 参数

    • sem:指向信号量对象的指针。

  • 返回值

    • 成功时返回 0

    • 失败时返回 -1 并设置 errno

发布信号量(V操作)

int sem_post(sem_t *sem); // V()
  • 功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量的值加 1。如果有线程因等待该信号量而阻塞,则唤醒其中一个线程。

  • 参数

    • sem:指向信号量对象的指针。

  • 返回值

    • 成功时返回 0

    • 失败时返回 -1 并设置 errno

基于环形队列的⽣产消费模型 

 环形队列(也称为循环缓冲区)是一种高效的数据结构,用于在生产者和消费者之间传递数据。在这种模型中,生产者负责生成数据并将其放入队列,而消费者则从队列中取出数据进行处理。环形队列通过使用固定大小的缓冲区来实现高效的数据交换,避免了动态内存分配的开销。

基本元素:

  1. 缓冲区数组:一个固定大小的数组,用于存储数据。

  2. 头指针(head):指向队列中第一个有效数据的位置。

  3. 尾指针(tail):指向队列中下一个可写位置。

  4. 容量(N):缓冲区的大小,即最多可以存储的数据项数。

操作

  1. 生产者操作(生产数据)

    • 生产者首先检查缓冲区是否有空间(即 tail 指针是否小于 head 指针加上缓冲区大小)。

    • 如果有空间,生产者将数据写入 tail 指针指向的位置,然后更新 tail 指针。

    • 如果没有空间,生产者可能需要等待或采取其他措施。

  2. 消费者操作(消费数据)

    • 消费者首先检查缓冲区是否有数据(即 head 指针是否小于 tail 指针)。

    • 如果有数据,消费者从 head 指针指向的位置读取数据,然后更新 head 指针。

    • 如果没有数据,消费者可能需要等待或采取其他措施。

同步和互斥

由于生产者和消费者可能同时访问环形队列,因此需要使用同步机制来避免数据竞争和不一致的问题:

  1. 互斥锁(Mutex)

    • 确保在任何时刻只有一个生产者或消费者可以访问环形队列。

    • 通过锁定和解锁操作来控制对队列的访问。

  2. 信号量(Semaphore)

    • data 信号量用于控制数据项的数量,确保消费者不会在没有数据时读取。

    • space 信号量用于控制缓冲区空间的数量,确保生产者不会在没有空间时写入。

只有在为满为空时指向同一个位置  而当其他位置时 两者之间是解耦的 

相关文章:

共享栈 线程局部存储 线程互斥 线程同步 消费者生产者模型

共享栈 第一个主线程会在栈区 而当其他线程创建时实在共享区动态申请的栈区 线程局部存储 __thread 关键字 与编译有关 全局变量是被线程共享的 每个线程都能看到 修改 但是如果对该全局变量加上__thread关键字后 该全局变量就不会被共享 将变量在库中的每一个线程的属…...

停车场停车位数据集,标注停车位上是否有车,平均正确识别率99.5%,支持yolov5-11, coco json,darknet,xml格式标注

停车场停车位数据集&#xff0c;标注停车位上是否有车&#xff0c;平均正确识别率98.0&#xff05;&#xff0c;支持yolov5-11&#xff0c; coco json&#xff0c;darknet&#xff0c;xml格式标注 数据集-识别停车场所有车辆的数据集 数据集分割 一共184张图片 训练组 89&am…...

【Go】运算符笔记

基本数学运算 Go 语言支持常见的 算术运算符&#xff0c;用于执行数学计算。 运算符说明加法-减法*乘法/除法%取余自增--自减 整数运算只能得到整数部分 package mainimport ("fmt""math" )func main() {go_math() }func go_math() {x, y : 8, 5fmt.Pr…...

ssm框架之mybatis框架讲解

1&#xff0c;Mybatis 1.1 Mybatis概述 1.1.1 Mybatis概念 MyBatis 是一款优秀的持久层框架&#xff0c;用于简化 JDBC 开发 MyBatis 本是 Apache 的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code&#xff0c;并且改名为MyBatis 。2…...

CEF 多进程模式时,注入函数,获得交互信息

CEF 控制台添加一函数,枚举 注册的供前端使用的CPP交互函数有哪些-CSDN博客 上篇文章,是在模拟环境,单进程中设置的,这篇文章,将其改到正常多进程环境中设置。 对应于工程中的 CEF_RENDER项目 一、多进程模式中,改写 修改步骤 1、注入函数 client_app_render.cpp 在…...

Androidstudio出现警告warning:意外的元素

这些警告信息通常与 Android SDK 或系统镜像的配置文件有关&#xff0c;可能是由于 SDK 工具或系统镜像的版本不兼容或配置文件格式发生了变化。以下是解决这些警告的步骤&#xff1a; 1. 更新 Android SDK 工具 确保你使用的是最新版本的 Android SDK 工具&#xff1a; 打开…...

深入了解Linux —— git三板斧

版本控制器git 为了我们方便管理不同版本的文件&#xff0c;就有了版本控制器&#xff1b; 所谓的版本控制器&#xff0c;就是能够了解到一个文件的历史记录&#xff08;修改记录&#xff09;&#xff1b;简单来说就是记录每一次的改动和版本迭代的一个管理系统&#xff0c;同…...

Vala编程语言教程-运算符

运算符 ‌ 赋值操作。左操作数必须为标识符&#xff0c;右操作数必须为适当的值或引用。 ‌, -, /, *, %‌ 基础算术运算&#xff0c;作用于左右操作数。 运算符也可用于字符串拼接。 ‌, -, /, *, %‌ 左右操作数间算术运算&#xff0c;左操作数必须为标识符&#xff0c;运…...

C#本地将labelme数据集转换为机器视觉yolo数据集格式

C#本地&#xff0c;将labelme数据集转换为机器视觉yolo数据集格式 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.Encodings.Web; using System.Text.RegularExpressions; using System.Text.U…...

【软件系统架构】单体架构

一、引言 在软件开发的漫长历程中&#xff0c;架构的选择一直是至关重要的决策。单体架构作为一种经典的架构模式&#xff0c;曾经在许多项目中发挥着不可替代的作用。虽然如今微服务等架构逐渐流行&#xff0c;但理解单体架构对于深入掌握软件架构体系仍然有着重要意义。 二、…...

【求助】【建议放弃】【谷粒商城版】Kubernetes

本文作者&#xff1a; slience_me 文章目录 Kubernetes【谷粒商城版】【建议放弃】1. docker安装2. kubernetes安装前3. kubeadm,kubelet,kubectl3.1 简介kubeadmkubeletkubectl常用指令 3.2 安装3.3 kubeadm初始化3.4 加入从节点(工作节点)3.5 安装Pod网络插件&#xff08;CNI…...

uniapp 实现微信小程序电影选座功能

拖动代码 /*** 获取点击或触摸事件对应的座位位置* 通过事件对象获取座位的行列信息* param {Event|TouchEvent} event - 点击或触摸事件对象* returns {Object} 返回座位位置对象&#xff0c;包含行(row)和列(col)信息&#xff0c;若未找到有效位置则返回 {row: -1, col: -1}*…...

python+flask实现360全景图和stl等多种格式模型浏览

1. 安装依赖 pip install flask 2. 创建Flask应用 创建一个基本的Flask应用&#xff0c;并设置路由来处理不同的文件类型。 from flask import Flask, render_template, send_from_directory app Flask(__name__) # 设置静态文件路径 app.static_folder static app.r…...

IntelliJ 配置文件plugin.xml

在 IntelliJ IDEA 插件开发中&#xff0c;plugin.xml 是插件的配置文件&#xff0c;它包含了关于插件的所有基本信息、扩展点、依赖关系等。该文件使用 XML 格式进行定义。以下是 plugin.xml 中常见的元素及其用途&#xff1a; <idea-plugin><!-- 插件的基本信息 --&…...

C# Unity 唐老狮 No.10 模拟面试题

本文章不作任何商业用途 仅作学习与交流 安利唐老狮与其他老师合作的网站,内有大量免费资源和优质付费资源,我入门就是看唐老师的课程 打好坚实的基础非常非常重要: Unity课程 - 游习堂 - 唐老狮创立的游戏开发在线学习平台 - Powered By EduSoho C# 1. 内存中&#xff0c;堆和…...

数据库系统——规范化1NF~BCNF

数据库规范化完全指南&#xff1a;从零到BCNF&#xff0c;中学生也能秒懂&#xff01;&#x1f4da;✨ 一、什么是数据库规范化&#xff1f; 科学定义 &#x1f50d; 数据库规范化是通过一系列规则&#xff08;范式&#xff09;将数据库表结构分解为更小、更高效、无冗余的表…...

第十五届蓝桥杯2024JavaB组省赛试题A:报数游戏

简单的找规律题目。题目给得数列&#xff0c;第奇数项是20的倍数&#xff0c;第偶数项时24的倍数。题目要求第n 202420242024 项是多少。这一项是偶数&#xff0c;所以答案一定是24的倍数&#xff0c;并且偶数项的个数和奇数项的个数各占一半&#xff0c;所以最终的答案ans( n…...

Matlab 汽车二自由度转弯模型

1、内容简介 Matlab 187-汽车二自由度转弯模型 可以交流、咨询、答疑 2、内容说明 略 摘 要 本文前一部分提出了侧偏角和横摆角速度作为参数。描述了车辆运动的运动状态&#xff0c;其中文中使用的参考模型是二自由度汽车模型。汽车速度被认为是建立基于H.B.Pacejka的轮胎模…...

关于 2>/dev/null 的作用以及机理

每个进程都有三个标准文件描述符&#xff1a;stdin&#xff08;标准输入&#xff09;、stdout&#xff08;标准输出&#xff09;和stderr&#xff08;标准错误&#xff09;。默认情况下&#xff0c;stderr会输出到终端。使用2>可以将stderr重定向到其他地方&#xff0c;比如…...

学c++的人可以几天速通python?

学了俩天啊&#xff0c;文章写纸上了 还是蛮有趣的...

HTML,CSS,JavaScript

HTML:负责网页的结构(页面元素和内容)。 CSS:负责网页的表现(页面元素的外观、位置等页面样式&#xff0c;如:颜色、大小等)。 Javascript:负责网页的行为(交互效果)。 MDN前端开发文档(MDN Web Docs) HTML HTML(HyperText Markup Language):超文本标记语言超文本:超越了文本的…...

微信小程序面试内容整理-图片优化

在微信小程序中,图片优化是提升加载速度、节省网络带宽和提高用户体验的重要步骤。图片通常是小程序页面中的主要资源,合理的图片优化能显著提高小程序的性能,尤其是在用户网络状况较差的情况下。 1. 选择合适的图片格式 不同的图片格式有不同的特点,选择合适的格式能够有效…...

Rocky Linux 9.x 基于 kubeadm部署k8s 1.32

一、部署说明 1、主机操作系统说明 序号操作系统及版本备注1Rocky Linux release 9下载链接&#xff1a;https://mirrors.163.com/rocky/9.5/isos/x86_64/Rocky-9.5-x86_64-minimal.iso 2、主机硬件配置说明 作用IP地址操作系统配置关键组件k8s-master01192.168.234.51Rocky…...

【每日学点HarmonyOS Next知识】上下拉列表、停止无限循环动画、页面列表跟随列表滑动、otf字体、日期选择

1、HarmonyOS 实现只需要保留上拉加载更多&#xff0c;但是不需要下拉刷新&#xff1f; Refresh通过参数refreshing判断当前组件是否正在刷新&#xff0c;可以控制该参数变化来触发下拉刷新&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5…...

解决git init 命令不显示.git

首先在自己的项目代码右击 打开git bash here 输入git init 之后自己的项目没有.git文件&#xff0c;有可能是因为.git文件隐藏了&#xff0c;下面是解决办法...

利用AI让数据可视化

1. 从问卷星上下载一份答题结果。 序号用户ID提交答卷时间所用时间来源来源详情来自IP总分1、《中华人民共和国电子商务法》正式实施的时间是&#xff08;&#xff09;。2、&#xff08;&#xff09;可以判断企业在行业中所处的地位。3、&#xff08;&#xff09;是指店铺内有…...

神经网络微调技术解析

神经网络微调技术 微调&#xff08;Fine-tuning&#xff09;是迁移学习的核心技术&#xff0c;通过在预训练模型基础上调整参数&#xff0c;使其适应特定任务或领域。以下从传统方法、参数高效微调&#xff08;PEFT&#xff09;、新兴技术三个维度展开&#xff0c;覆盖主流技术…...

WebLogic XMLDecoder反序列化漏洞(CVE-2017-10271)深度解析与实战复现

0x00 漏洞概述 CVE-2017-10271 是Oracle WebLogic Server WLS Security组件中的远程代码执行漏洞。攻击者通过构造恶意XML请求&#xff0c;利用XMLDecoder反序列化机制绕过安全验证&#xff0c;最终实现服务器权限接管。 影响版本 WebLogic 10.3.6.0WebLogic 12.1.3.0WebLog…...

解决qt中自定插件加载失败,不显示问题。

这个问题断断续续搞了一天多&#xff0c;主要是版本不匹配问题。 我们先来看下 Based on Qt 6.6.0 → 说明 Qt Creator 本身 是基于 Qt 6.6.0 框架构建的。MSVC 2019, 64-bit → 说明 Qt Creator 是使用 Microsoft Visual C 2019 编译器&#xff08;64 位&#xff09; 编译的。…...

Git 面试问题,解决冲突

1.问题描述 在多人协作开发中&#xff0c;当多个开发者在同一文件的同一部分进行修改并提交时&#xff0c;Git 无法自动合并这些更改&#xff0c;从而产生代码冲突&#xff08;Conflict&#xff09;。冲突的代码会被 Git 标记出来&#xff0c;需要开发者手动解决。 冲突原因 多…...