21xrx.com
2024-09-20 00:26:25 Friday
登录
文章检索 我的文章 写文章
C++多线程同步锁技术详解
2023-06-28 08:01:47 深夜i     --     --
C++ 多线程 同步锁 技术 详解

随着计算机技术的不断发展,软件开发的需求也越来越复杂。多线程编程是一种常用的技术,可以提高程序的效率,但同时也会带来一些问题,如数据访问冲突和资源竞争等。这时,我们就需要使用同步锁技术。

C++是一种支持多线程编程的语言,具备丰富的同步锁技术,本文将详细介绍其中的常见锁类型以及它们的特点。

1. 互斥锁(mutex)

互斥锁是最常用的锁类型,它能够保护共享资源,避免多个线程同时访问。当一个线程获得了互斥锁之后,其他线程就无法访问受保护的资源,直到该线程释放互斥锁为止。

示例代码:


#include <mutex>

#include <thread>

#include <iostream>

std::mutex g_mutex;

int g_count = 0;

void threadFunc()

{

  for (int i = 0; i < 10; ++i) {

    g_mutex.lock();

    std::cout << "Thread " << std::this_thread::get_id() << " count: " << ++g_count << std::endl;

    g_mutex.unlock();

  }

}

int main()

{

  std::thread t1(threadFunc);

  std::thread t2(threadFunc);

  t1.join();

  t2.join();

  return 0;

}

在上面的示例代码中,我们声明了一个全局变量`g_count`,并使用互斥锁`g_mutex`保护它。两个线程`t1`和`t2`都会访问`g_count`,但是由于我们使用了互斥锁,所以只有一个线程能够获得锁,进入临界区访问资源。

2. 递归锁(recursive_mutex)

递归锁与互斥锁类似,都是用于保护共享资源的,但是递归锁允许同一个线程多次获取锁,避免死锁。递归锁和互斥锁的区别在于,如果一个线程多次获取一个互斥锁,那么会出现死锁的情况,而递归锁则会允许这种操作。

示例代码:


#include <mutex>

#include <thread>

#include <iostream>

std::recursive_mutex g_mutex;

int g_count = 0;

void threadFunc()

{

  for (int i = 0; i < 10; ++i) {

    g_mutex.lock();

    g_mutex.lock();

    std::cout << "Thread " << std::this_thread::get_id() << " count: " << ++g_count << std::endl;

    g_mutex.unlock();

    g_mutex.unlock();

  }

}

int main()

{

  std::thread t1(threadFunc);

  std::thread t2(threadFunc);

  t1.join();

  t2.join();

  return 0;

}

在上面的示例代码中,我们使用递归锁`g_mutex`保护全局变量`g_count`。两个线程`t1`和`t2`都会访问`g_count`,并多次获取递归锁`g_mutex`。由于递归锁允许同一个线程多次获取锁,所以不会出现死锁的情况。

3. 读写锁(shared_mutex)

读写锁是一种特殊的锁类型,它允许多个线程同时读取共享资源,但是在写操作时保证资源唯一性。读写锁降低了对数据的锁定粒度,提高了程序并发度,常用于读多写少的场景。

示例代码:


#include <shared_mutex>

#include <thread>

#include <iostream>

std::shared_mutex g_mutex;

int g_count = 0;

void writeThreadFunc()

{

  for (int i = 0; i < 10; ++i) {

    g_mutex.lock();

    std::cout << "Write Thread " << std::this_thread::get_id() << " count: " << ++g_count << std::endl;

    g_mutex.unlock();

  }

}

void readThreadFunc()

{

  for (int i = 0; i < 10; ++i) {

    g_mutex.lock_shared();

    std::cout << "Read Thread " << std::this_thread::get_id() << " count: " << g_count << std::endl;

    g_mutex.unlock_shared();

  }

}

int main()

{

  std::thread t1(writeThreadFunc);

  std::thread t2(readThreadFunc);

  t1.join();

  t2.join();

  return 0;

}

在上面的示例代码中,我们使用读写锁`g_mutex`保护全局变量`g_count`。两个线程`t1`和`t2`都会访问`g_count`,其中`t1`负责写操作,而`t2`负责读操作。在读操作时,我们使用了`g_mutex.lock_shared()`和`g_mutex.unlock_shared()`来获取和释放读锁。

总结

在多线程编程中,同步锁技术可以用于保护共享资源,防止数据访问冲突和资源竞争。在C++中,我们可以使用互斥锁、递归锁和读写锁等锁类型来实现线程同步。

在使用锁的过程中,为了避免死锁和性能问题,需要注意以下几点:

1. 避免嵌套锁,尽可能使用多个单独的锁。

2. 尽可能使用局部变量代替全局变量,减少锁的竞争范围。

3. 尽量减短锁的占用时间,避免影响其他线程的执行。

4. 在使用递归锁时,需要注意锁的获取和释放次数,避免死锁。

5. 在使用读写锁时,需要根据场景选择读锁或写锁,以提高程序的并发度。

如果以上这些技巧都不能满足需求,还可以考虑使用其他同步机制,如条件变量、信号量等。领悟到这些同步锁技术的原理和使用方法,就能写出更高效、更稳定的多线程程序。

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复