C++并发编程中的锁的介绍(一)

简介: C++并发编程中的锁的介绍(一)

C++中的锁


C++中的锁机制


C++中的锁机制以下几种:


  • 互斥锁:包括std::mutex、std::recursive_mutex、std::timed_mutex、std::recursive_timed_mutex等。互斥锁用于保护共享资源,可以保证同一时刻只有一个线程访问共享资源。
  • 读写锁:包括std::shared_mutex、std::shared_timed_mutex等。读写锁允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。
  • 条件变量:包括std::condition_variable、std::condition_variable_any等。条件变量允许线程等待某个条件发生变化,只有当条件满足时才能继续执行。
  • 原子操作:包括std::atomic、std::atomic_flag等。原子操作用于保证某个操作的执行不会被其他线程中断,从而避免了数据竞争的发生。
  • 自旋锁:包括std::spin_lock、std::atomic_flag等。自旋锁在等待锁的过程中不断地循环检查锁是否可用,而不是放弃CPU,从而避免了线程上下文切换带来的开销。
  • 信号量:包括std::binary_semaphore、std::counting_semaphore等。信号量用于控制同时访问某个资源的线程数量,可以实现线程的互斥和同步。

悲观锁和乐观锁


在C++中,锁通常被分为两种类型:悲观锁和乐观锁

  • 其中悲观锁是指在访问共享资源时先获取锁,防止其他线程同时修改该资源,适用于写操作多的场景。C++中的互斥锁就是一种悲观锁。
  • 而乐观锁则是在不加锁的情况下,尝试去读取和修改共享资源,如果遇到冲突,再使用重试等机制解决冲突,适用于读操作多于写操作的场景。
  • 在C++中,可以使用atomic类型来实现乐观锁。atomic类型提供了对基本类型的原子操作,包括读、写、比较交换等。在进行原子操作时,它使用硬件原语实现同步,避免了使用锁所带来的额外开销和死锁的问题。
  • 除了atomic类型,C++11还引入了一些使用乐观锁的算法,如无锁队列和无锁哈希表等。这些算法使用原子操作来实现线程安全,同时充分利用了乐观锁的优势,避免了使用锁所带来的开销。

Mutex:互斥


所有线程间共享数据的问题,都是修改数据导致的(竞争条件) 。如果所有的共享数据都是只读的,就没问题,因为一个线程所读取的数据不受另一个线程是否正在读取相同的数据而影响


恶性条件竞争


恶性条件竞争通常发生于多线程对多于一个的数据块的修改时,产生了非预想的执行效果,即竞态条件是多个线程同时访问共享资源,导致结果依赖于线程执行的顺序和时间。

  • 竞态条件(Race Condition)指的是多个线程访问共享变量时,最终的结果取决于多个线程的执行顺序。竞态条件不一定总是错误的,但它们可能导致非预期的结果。
  • 数据竞争(Data Race)指的是多个线程同时访问同一个共享变量,并且至少有一个线程对该变量进行了写操作。数据竞争是一种错误,因为它可能导致未定义的行为。

在多线程编程中,竞态条件和数据竞争是常见的问题。解决这些问题的关键是使用同步机制。

避免恶性条件竞争:

  • 要避免恶性的条件竞争,一种方法是就使用一定的手段,对线程共享的内存区域的数据结构采用某种保护机制,如使用锁
  • 另一种就是选择对该区域的数据结构和不变量的设计进行修改,如保证该区域为原子操作,,修改完的结构必须能完成一系列不可分割的变化,但是这种无锁的方法很难一定保证线程安全
  • 另一种处理条件竞争的方式是,使用事务(transacting)的方式去处理该数据共享区域

mutex 头文件介绍


mutex 又称互斥量,C++11 中与 mutex 相关的类(包括锁类型)和函数都声明在 <mutex> 头文件中,所以如果你需要使用 std::mutex,就必须包含<mutex>头文件。


mutex系列类(四种)


  • std::mutex:基本的 mutex 类。
  • std::recursive_mutex:递归 mutex 类。
  • std::time_mutex:定时 mutex 类。
  • std::recursive_timed_mutex:定时递归 mutex 类。
函数
  • std::try_lock:尝试同时对多个互斥量上锁。
  • std::lock:可以同时对多个互斥量上锁。
  • std::call_once:如果多个线程需要同时调用某个函数,call_once 可以保证多个线程对该函数只调用一次。
目录
相关文章
|
6月前
|
存储 前端开发 Java
【C++ 多线程 】C++并发编程:精细控制数据打印顺序的策略
【C++ 多线程 】C++并发编程:精细控制数据打印顺序的策略
186 1
|
2月前
|
Linux API C++
超级好用的C++实用库之互斥锁
超级好用的C++实用库之互斥锁
27 2
|
6月前
|
Linux API C++
c++多线程——互斥锁
c++多线程——互斥锁
|
6月前
|
C++
C++11 std::lock_guard 互斥锁
C++11 std::lock_guard 互斥锁
48 0
|
6月前
|
算法 C++ 开发者
【C++ 20 并发工具 std::barrier】掌握并发编程:深入理解C++的std::barrier
【C++ 20 并发工具 std::barrier】掌握并发编程:深入理解C++的std::barrier
251 0
|
4月前
|
C++ 运维
开发与运维编译问题之在C++中在使用std::mutex后能自动释放锁如何解决
开发与运维编译问题之在C++中在使用std::mutex后能自动释放锁如何解决
65 2
|
6月前
|
存储 并行计算 Java
C++线程 并发编程:std::thread、std::sync与std::packaged_task深度解析(二)
C++线程 并发编程:std::thread、std::sync与std::packaged_task深度解析
245 0
|
5月前
|
安全 C++
C++一分钟之-互斥锁与条件变量
【6月更文挑战第26天】在C++并发编程中,`std::mutex`提供互斥访问,防止数据竞争,而`std::condition_variable`用于线程间的同步协调。通过`lock_guard`和`unique_lock`防止忘记解锁,避免死锁。条件变量需配合锁使用,确保在正确条件下唤醒线程,注意虚假唤醒和无条件通知。生产者-消费者模型展示了它们的应用。正确使用这些工具能解决同步问题,提升并发性能和可靠性。
57 4
|
5月前
|
存储 设计模式 安全
C++一分钟之-并发编程基础:线程与std::thread
【6月更文挑战第26天】C++11的`std::thread`简化了多线程编程,允许并发执行任务以提升效率。文中介绍了创建线程的基本方法,包括使用函数和lambda表达式,并强调了数据竞争、线程生命周期管理及异常安全等关键问题。通过示例展示了如何用互斥锁避免数据竞争,还提及了线程属性定制、线程局部存储和同步工具。理解并发编程的挑战与解决方案是提升程序性能的关键。
78 3
|
6月前
|
安全 Linux 编译器
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)(下)
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)
45 0