首页 > 编程语言 >【C/C++】5.并发控制

【C/C++】5.并发控制

时间:2024-10-29 23:42:15浏览次数:5  
标签:std 控制 C++ 信号量 并发 线程 include

并发控制(Concurrency Control)是指在多线程或多进程环境中,确保多个操作在共享资源上的访问不会发生冲突或产生不一致的情况。并发控制的核心目标是在允许并发操作的同时,保证系统的正确性、数据的一致性和完整性。

在并发环境下,不同的线程或进程可能会同时访问共享资源(例如变量、文件或数据库记录)。若没有适当的并发控制,可能会发生数据竞争(Race Condition)或死锁(Deadlock)等问题,导致系统出现错误或不稳定的状态。因此,并发控制是实现多线程或分布式系统时必须考虑的问题。

并发控制的主要问题

  1. 数据竞争(Race Condition)
    当多个线程同时读取和修改共享变量,且访问顺序不确定时,可能会导致数据竞争。例如,一个线程正在写数据,另一个线程正在读取数据,读到的可能是不完整或错误的结果。

  2. 死锁(Deadlock)
    当多个线程因相互等待对方释放资源而无限期地等待时,就会产生死锁。例如,线程A持有资源X并等待资源Y,而线程B持有资源Y并等待资源X,最终导致两个线程都无法继续。

  3. 资源饥饿(Starvation)
    某些线程由于得不到所需资源而一直无法执行,称为资源饥饿。例如,优先级较低的线程可能由于高优先级线程的持续占用而一直得不到运行机会。

  4. 数据不一致
    由于缺乏正确的并发控制,可能导致多个线程读取和写入共享数据,最终数据出现不一致的问题。例如,多个线程同时更新一个计数器,可能会导致最终计数不准确。


并发控制的常见机制

并发控制的核心是通过协调多个线程或进程对共享资源的访问,确保操作的正确性。以下是常见的并发控制机制:

1. 锁(Lock)

锁是并发控制中最常用的工具,用于限制同一时间内只有一个线程访问某个资源。常见的锁类型包括:

  • 互斥锁(Mutex):一种互斥机制,确保同一时间只有一个线程访问共享资源。其他线程必须等待,直到锁被释放。

      #include <iostream> #include <thread> #include <mutex> std::mutex mtx; void printSafe(const std::string& message) {   std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁   std::cout << message << std::endl; }
  • 读写锁(Read-Write Lock):允许多个线程同时读取数据,但当一个线程写入数据时,其它读写线程都必须等待。

  • 自旋锁(Spin Lock):一种简单的锁机制,线程在等待锁时会持续检查锁的状态,不进入休眠,适用于短时间的锁等待场景。

2. 信号量(Semaphore)

信号量是一种控制线程数目的同步机制。信号量有一个计数器,用于记录当前可用的资源数:

  • 计数信号量:可以设置允许的最大并发线程数,适合控制对有限资源的访问。
  • 二元信号量:与互斥锁相似,但可以实现更复杂的同步机制。
    #include <iostream>   #include <thread>   #include <semaphore.h> // C++20 中引入   std::counting_semaphore<1> semaphore(1);   void sharedFunction() {      semaphore.acquire(); // 获取信号量      // 临界区代码      std::cout << "Executing critical section" << std::endl;      semaphore.release(); // 释放信号量   }

3. 条件变量(Condition Variable)

条件变量是一种同步机制,允许线程在特定条件下等待。条件变量通常与互斥锁一起使用,以便线程在条件不满足时进入等待状态,条件满足时被唤醒。

    #include <iostream>   #include <thread>   #include <condition_variable>   #include <mutex>       std::mutex mtx;   std::condition_variable cv;   bool ready = false;       void waitFunction() {       std::unique_lock<std::mutex> lock(mtx);       cv.wait(lock, [] { return ready; }); // 等待条件满足       std::cout << "Proceeding after condition met" << std::endl;   }   void signalFunction() {      {         std::lock_guard<std::mutex> lock(mtx);         ready = true; // 设置条件      }      cv.notify_all(); // 唤醒等待线程   }

4. 原子操作(Atomic Operation)

原子操作是一种不可中断的操作,即使在多线程环境下,也不会被其他线程干扰。C++提供std::atomic来支持原子操作,可以有效避免数据竞争问题。

    #include <iostream>   #include <atomic>   #include <thread>   std::atomic<int> counter(0);   void increment() {      counter.fetch_add(1); // 原子性增加1   }

并发控制的应用场景

  • 银行账户系统:确保多个操作不会同时修改同一个账户的数据,防止因数据竞争导致的错误。
  • 生产者-消费者模型:使用条件变量或信号量来控制生产者和消费者对缓冲区的访问,防止数据丢失或重复读取。
  • 数据库系统:在多事务并发操作下确保数据的一致性和完整性,常使用锁和日志等方式实现并发控制。

并发控制的选择

  • 锁机制适用于需要严格控制访问顺序的情况,但需小心避免死锁。
  • 信号量更适合资源有限的场景,如限制同时访问某资源的线程数。
  • 原子操作适用于简单的共享变量操作,代价低且操作简单,但仅限于一些基本操作。
  • 条件变量适用于等待特定条件的场景,能够实现较高的线程协调效率。

标签:std,控制,C++,信号量,并发,线程,include
From: https://www.cnblogs.com/luckyyys/p/18514757

相关文章

  • 每日OJ题_牛客_AB20走迷宫_BFS_C++_Java
    目录牛客_AB20走迷宫_BFS题目解析C++代码Java代码牛客_AB20走迷宫_BFS走迷宫_牛客题霸_牛客网(nowcoder.com)描述:        给定一个n×m的网格,在网格中每次在不超过边界的情况下可以选择向上、向下、向左、向右移动一格。网格中的一些格子上放置有障碍物,放有......
  • qt的c++环境配置和c++基础【正点原子】嵌入式Qt5 C++开发视频
    QTc++环境配置和c++基础c++环境配置和工程创建  1.配置步骤  2.新建qt工程目录和工程  3.重启qt后打开最近的qt项目c++基础-类和对象  1.什么是类和对象    A.类的定义    B.类的结构表示    C.类的访问权限    D.对象的定义    E.类和......
  • 什么时候用C而不用C++
    在选择编程语言时,我们可能会在C和C++之间犹豫。C语言通常用于低级别的系统编程、嵌入式系统开发、操作系统组件、与硬件密切相关的软件、对性能要求极高的应用以及早期使用C语言编写且维护成本较低的项目。而C++以其面向对象特性、灵活的抽象能力、类和模板等特性而广泛应用于软......
  • C++中结构体是使用实例还是指针
    在C++中,结构体(struct)可以通过指针或直接实例来定义。选择使用指针或直接实例化结构体取决于几个因素,包括内存管理、性能、语义和使用场景。以下是一些常见的考虑因素:1. 内存管理:指针:使用指针时,结构体的实例通常在堆上分配。这允许动态管理内存,可以在运行时决定结构体的......
  • 003:通过按键控制LED亮灭
    这里我就单纯的展示下通过按键控制LED亮灭的方法,不考虑按键消抖和其他的问题。话不多说直接展示代码:#include"stm32f10x.h"//Deviceheader#defineLED_PINGPIO_Pin_5//假设LED连接到GPIOA的第5个引脚#defineBUTTON_PINGPIO_Pin_1//假设按键连......
  • 并发编程(1)——线程
    目录一、day11.线程的建立1.1线程如何发起1.1.1普通函数1.1.2仿函数1.1.3lambda函数1.1.4类的成员函数1.1.5move1.2子线程需要被等待1.3detach1.4.异常处理1.5慎重使用隐式转换1.6如何在线程中使用引用2.thread参数传递和调用原理2.1数据成员2.......
  • 【OJ题解】C++ 把字符串转换成整数
    ......
  • Python控制结构
    在编程的世界里,控制结构就像是一位指挥家,能够引导程序按顺序演奏出美妙的乐章。今天,我们将深入探讨Python中的条件判断和循环结构,当然,不会忘记用幽默的方式来让这些概念更易懂!条件判断条件判断是控制程序流的重要组成部分。我们常用的 if-elif-else 结构就像是生活中的选......
  • 如何区分工程招标过程中的控制价、拦标价与标底价?蓝燕云项目投标管理专家分享。
    在招投标过程中,控制价、拦标价与标底价这三个概念常常被提及,但它们之间那些不为人知的区别,你是否真正了解呢?01各自的定义控制价:在工程发包进程里,招标人依据相关计价规定算出的工程造价。它就像是一道“天花板”,是招标人用于对招标工程发包设定的最高控制限价,在某些地方,它还......
  • 流程控制(上)
    三、流程控制上什么是流程?根据把大象装进冰箱分几步可以解释1、打开冰箱2、把大象装进去3、关冰箱在程序中流程就是代码执行的过程在Python当中主要的流程分3大结构:顺序结构(目前)、分支结构、循环结构顺序结构:程序从头到尾的顺序依次执行每一条Python代码。分支......