21xrx.com
2024-12-22 20:54:25 Sunday
登录
文章检索 我的文章 写文章
C++多线程编程指南
2023-07-12 15:43:55 深夜i     --     --
C++ 多线程编程 指南 并发编程 线程安全

在现代计算机系统中,多线程编程已成为一种必不可少的技能。相比于单线程,使用多线程在动态分布式系统中具有更好的性能表现。而 C++ 作为一种被广泛使用的编程语言,其多线程编程模块将能帮助开发者更好地优化代码并充分利用系统资源。

本指南将介绍一些常见的 C++ 多线程编程技术以及相关的库和工具。在本指南中,我们将从 C++ 多线程编程的基本概念开始,逐步深入探讨线程的创建、同步、信号量、互斥锁、原子操作以及内存模型等。

线程的创建

C++ 11 提供了一个 std::thread 库,它使得线程的创建变得简单明了。我们可以使用 std::thread::thread() 构造函数对线程进行创建。例如:

#include

#include

void thread_func()

{

  std::cout << "Hello, C++ multi-threading world!" << std::endl;

}

int main()

{

  std::thread t(thread_func);

  t.join();

  return 0;

}

以上代码展示了如何使用 std::thread 。我们首先在主线程中构造了一个 std::thread 实例 t ,并将它与我们要执行的函数 thread_func 关联起来。最后我们调用了线程对象的 join() 方法,等待线程的结束。

同步

在 C++ 中,线程同步是使用 std::mutex 和 std::lock_guard 来保证同步的。例如:

#include

#include

#include

std::mutex mtx;

void thread_func()

{

  std::lock_guard lock(mtx);

  std::cout << "Hello, C++ multi-threading world!" << std::endl;

}

int main()

{

  std::thread t(thread_func);

  t.join();

  return 0;

}

以上代码中,我们使用 std::mutex 必要时保护共享数据的访问,并使用 std::lock_guard 简化锁的管理。

信号量

信号量是一种广泛使用的同步机制。在 C++ 中,可以使用 std::counting_semaphore 来实现信号量。例如:

#include

#include

#include

std::counting_semaphore<> sem(1);

void thread_func()

{

  sem.acquire();

  std::cout << "Hello, C++ multi-threading world!" << std::endl;

  sem.release();

}

int main()

{

  std::thread t(thread_func);

  t.join();

  return 0;

}

以上代码中,我们使用 std::counting_semaphore 对一项操作进行计数,并使用 acquire() 和 release() 方法来将计数器的值调整为正确的值。当计数器为零时,acquire() 方法将阻塞,直到另一线程 release() 信号量。

互斥锁

互斥锁是另一种用于线程同步的机制。在 C++ 中,可以使用 std::recursive_mutex 来实现互斥锁。例如:

#include

#include

#include

std::recursive_mutex rmtx;

void thread_func(int n)

{

  std::lock_guard lock(rmtx);

  std::cout << "n = " << n << std::endl;

  if (n > 0) {

    thread_func(n - 1);

  }

}

int main()

{

  std::thread t(thread_func, 3);

  t.join();

  return 0;

}

以上代码展示了如何使用 std::recursive_mutex 来实现递归线程,以及其它复杂的算法。

原子操作

在 C++ 中,可以通过 std::atomic 来进行原子操作。例如:

#include

#include

#include

std::atomic cnt(0);

void thread_func()

{

  cnt.fetch_add(1);

}

int main()

{

  std::thread t1(thread_func);

  std::thread t2(thread_func);

  std::thread t3(thread_func);

  t1.join();

  t2.join();

  t3.join();

  std::cout << "cnt = " << cnt << std::endl;

  return 0;

}

以上代码中,我们使用 std::atomic 获取整数计数器的值,并使用 fetch_add() 来递增计数器的值。

内存模型

C++ 的内存模型是多线程编程的重点之一。在 C++ 中,我们可以使用 std::atomic 的内存模型来对总线嗅探等间接内存访问产生的问题进行解决。例如:

#include

#include

std::atomic cnt(0);

void thread_func()

{

  cnt.fetch_add(1, std::memory_order_relaxed);

  cnt.fetch_sub(1, std::memory_order_relaxed);

  cnt.fetch_add(1, std::memory_order_seq_cst);

}

int main()

{

  std::thread t1(thread_func);

  std::thread t2(thread_func);

  std::thread t3(thread_func);

  t1.join();

  t2.join();

  t3.join();

  std::cout << "cnt = " << cnt << std::endl;

  return 0;

}

以上代码中,我们使用 std::atomic 的内存模型来保证并发访问计数器时的互斥性。

结论

本文介绍了 C++ 多线程编程的基本概念,包括线程的创建、同步、信号量、互斥锁、原子操作以及内存模型等。搭配实例代码,可以帮助大家对 C++ 多线程编程有更深层次的理解和掌握。在日常开发中,我们应该根据不同问题选用不同的技术,并结合并发访问的属性选择合适的方法,来保证代码高效稳定。

  
  

评论区

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